Skip to content

docs: add v2.0.0 patch notes to the changelog #572

docs: add v2.0.0 patch notes to the changelog

docs: add v2.0.0 patch notes to the changelog #572

Workflow file for this run

# AsyncAO CI: lint + race tests + alloc-gated benchmarks, then binary builds
# for every platform. Pull requests get downloadable binaries as artifacts.
#
# Each platform builds TWICE via a `variant` matrix: the full default binary
# (Discord Rich Presence bundled — pure stdlib IPC, no DLL, off by default; voice
# chat included) and a lean `-tags "nodiscord novoice"` binary with BOTH the
# Discord integration and the LemmyAO/Nyathena voice chat compiled out entirely.
# Neither is ever a forced dependency; the second artifact exists for anyone who
# wants a binary with zero Discord and zero voice code at all.
name: CI
on:
push:
branches: ["**"]
pull_request:
workflow_dispatch:
env:
GO_VERSION: "1.24"
jobs:
test:
name: Lint & race tests (Linux)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
- name: Install SDL2 + libwebp + libavif dev packages
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
libsdl2-dev libsdl2-ttf-dev libwebp-dev libavif-dev libopus-dev libopusfile-dev cmake ninja-build pkg-config
- name: Build + install SDL Mixer X (crossfade + gapless loop points)
run: |
sudo bash scripts/build-sdl-mixer-x.sh /usr/local
echo "CGO_CFLAGS=-I/usr/local/include $(pkg-config --cflags sdl2)" >> "$GITHUB_ENV"
echo "CGO_LDFLAGS=-L/usr/local/lib" >> "$GITHUB_ENV"
- name: go vet
run: go vet ./...
# PINNED, not "latest". A floating version hands our CI to someone else's
# release schedule: 2026.2 landed 2026-08-20 and 2026.2.1 the day after,
# and the next push went red on SA4006 that the older staticcheck installed
# locally never reported — so it passed every local gate on the way in and
# only CI saw it (dfd514d). This job also gates every binary build below,
# so an upstream release can block a release mid-flight. Bump this
# deliberately: install the same version locally (go install
# honnef.co/go/tools/cmd/staticcheck@<version>), clear what it finds, and
# move the pin in the same commit.
- name: staticcheck
uses: dominikh/staticcheck-action@v1
with:
version: "2026.2.1"
install-go: false
- name: Tests (race detector — §17.8 gate)
run: go test -race -timeout 600s -count=1 ./...
- name: "Tests (lean build — Discord + voice compiled out; nodiscord+novoice stubs must build & pass)"
run: go test -tags "nodiscord novoice" -timeout 600s -count=1 ./...
- name: Benchmarks (alloc gates — §15)
run: |
go test -run=NONE -bench=. -benchmem -benchtime=200ms -count=1 ./... | tee bench.txt
# Gate: the learned resolver path must stay ≤ 1 alloc/op and the
# cache hits + render frame at 0 allocs/op.
! grep -E "BenchmarkBuildCandidates_Learned.* *[2-9] allocs/op" bench.txt
! grep -E "BenchmarkCacheHit_T[12].* *[1-9] allocs/op" bench.txt
! grep -E "BenchmarkRenderFrame.* *[1-9] allocs/op" bench.txt
- name: Upload benchmark results
uses: actions/upload-artifact@v4
with:
name: benchmarks
path: bench.txt
build-linux:
name: Binary (Linux x86_64)${{ matrix.variant.label }}
runs-on: ubuntu-latest
needs: test
strategy:
matrix:
variant:
- { label: "", tags: "", suffix: "" }
- { label: " - Discord-free, no voice", tags: "nodiscord novoice", suffix: "-nodiscord" }
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
- name: Install SDL2 + libwebp + libavif dev packages
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
libsdl2-dev libsdl2-ttf-dev libwebp-dev libavif-dev libopus-dev libopusfile-dev cmake ninja-build pkg-config
- name: Build + install SDL Mixer X (crossfade + gapless loop points)
run: |
sudo bash scripts/build-sdl-mixer-x.sh /usr/local
echo "CGO_CFLAGS=-I/usr/local/include $(pkg-config --cflags sdl2)" >> "$GITHUB_ENV"
echo "CGO_LDFLAGS=-L/usr/local/lib" >> "$GITHUB_ENV"
- name: Build
run: |
go build -tags "${{ matrix.variant.tags }}" -pgo=auto -trimpath -ldflags "-s -w" -o asyncao ./cmd/asyncao
- uses: actions/upload-artifact@v4
with:
name: asyncao-linux-x86_64${{ matrix.variant.suffix }}
path: asyncao
build-windows:
name: Binary (Windows x86_64)${{ matrix.variant.label }}
runs-on: windows-latest
needs: test
strategy:
matrix:
variant:
- { label: "", tags: "", suffix: "" }
- { label: " - Discord-free, no voice", tags: "nodiscord novoice", suffix: "-nodiscord" }
defaults:
run:
shell: msys2 {0}
steps:
- uses: actions/checkout@v4
- uses: msys2/setup-msys2@v2
with:
msystem: UCRT64
update: true
install: >-
mingw-w64-ucrt-x86_64-gcc
mingw-w64-ucrt-x86_64-pkgconf
mingw-w64-ucrt-x86_64-cmake
mingw-w64-ucrt-x86_64-ninja
mingw-w64-ucrt-x86_64-SDL2
mingw-w64-ucrt-x86_64-SDL2_ttf
mingw-w64-ucrt-x86_64-libwebp
mingw-w64-ucrt-x86_64-libavif
mingw-w64-ucrt-x86_64-opus
mingw-w64-ucrt-x86_64-opusfile
git
- uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
# setup-go only edits the *Windows* PATH and no longer exports GOROOT
# (that stopped at Go 1.9), while the msys2 shell rebuilds a minimal
# PATH of its own — so the toolchain is invisible in the build step.
# Publish GOROOT via GITHUB_ENV; non-PATH env vars do cross into MSYS2.
- name: Expose GOROOT to the MSYS2 shell
shell: pwsh
run: |
"GOROOT=$(go env GOROOT)" | Out-File -FilePath $env:GITHUB_ENV -Append
- name: Build + install SDL Mixer X (crossfade + gapless loop points)
run: |
bash scripts/build-sdl-mixer-x.sh /ucrt64
echo "CGO_CFLAGS=-I/ucrt64/include $(pkg-config --cflags sdl2)" >> "$GITHUB_ENV"
echo "CGO_LDFLAGS=-L/ucrt64/lib" >> "$GITHUB_ENV"
- name: Build + bundle DLLs
run: |
export PATH="$(cygpath -u "$GOROOT")/bin:$PATH"
export CGO_ENABLED=1
go build -tags "${{ matrix.variant.tags }}" -pgo=auto -trimpath -ldflags "-s -w" -o dist/asyncao.exe ./cmd/asyncao
# Ship the runtime DLLs next to the exe so it runs anywhere.
ldd dist/asyncao.exe | grep -io '/ucrt64/bin/[a-z0-9_.+-]*\.dll' | sort -u | while read -r dll; do
cp "$dll" dist/
done
- uses: actions/upload-artifact@v4
with:
name: asyncao-windows-x86_64${{ matrix.variant.suffix }}
path: dist/
build-macos:
name: Binary (macOS arm64)${{ matrix.variant.label }}
runs-on: macos-latest
needs: test
strategy:
matrix:
variant:
- { label: "", tags: "", suffix: "" }
- { label: " - Discord-free, no voice", tags: "nodiscord novoice", suffix: "-nodiscord" }
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
# dylibbundler is needed by scripts/bundle-macos.sh. Ogg-Opus MUSIC
# decode/seek comes from the opusfile FORMULA, hard-linked into
# libSDL2_mixer by its formula (--enable-music-opus with the shared/dlopen
# path disabled); the bare `opus` formula is only the codec (voice chat)
# and provides no Ogg demuxing/seeking. brew already pulls opusfile as an
# sdl2_mixer dependency — naming it here pins that requirement explicitly
# (release.yml installs the same list — keep them consistent).
- name: Install SDL2 + libwebp + libavif
run: brew install sdl2 sdl2_ttf webp libavif opus opusfile cmake ninja pkg-config dylibbundler
- name: Build + install SDL Mixer X (crossfade + gapless loop points)
run: |
bash scripts/build-sdl-mixer-x.sh "$(brew --prefix)"
echo "CGO_CFLAGS=-I$(brew --prefix)/include $(pkg-config --cflags sdl2)" >> "$GITHUB_ENV"
echo "CGO_LDFLAGS=-L$(brew --prefix)/lib" >> "$GITHUB_ENV"
- name: Build
run: |
export CGO_ENABLED=1
# Embed NSHighResolutionCapable so the bare binary (no .app/Info.plist)
# still gets a 2x Retina backing store on macOS instead of 1x compat mode.
go build -tags "${{ matrix.variant.tags }}" -pgo=auto -trimpath -ldflags "-s -w -extldflags=-Wl,-sectcreate,__TEXT,__info_plist,$PWD/packaging/macos/Info.plist" -o asyncao ./cmd/asyncao
# Run the release-time dylib bundler here too, BLOCKING, purely for its
# built-in otool assertion: if a new dependency ever links against a
# Homebrew path that the bundler can't rewrite, this fails the build and
# catches the "Library not loaded on a clean Mac" regression before release.
- name: Bundle dylibs + assert no Homebrew paths remain
run: |
bash scripts/bundle-macos.sh asyncao macos-stage
- uses: actions/upload-artifact@v4
with:
name: asyncao-macos-arm64${{ matrix.variant.suffix }}
path: asyncao
# The bare Linux binary above runs only where SDL2/webp/avif are already
# installed. This job packages a self-contained AppImage — one executable that
# bundles the runtime libraries — so non-Windows users get a download that
# "just works" like the Windows DLL bundle does. (Default variant; the
# Discord-free flavor remains available as the bare binary artifact.)
appimage-linux:
name: AppImage (Linux x86_64)${{ matrix.variant.label }}
runs-on: ubuntu-latest
needs: test
strategy:
matrix:
variant:
- { label: "", tags: "", suffix: "", output: "AsyncAO-x86_64.AppImage" }
- { label: " - Discord-free, no voice", tags: "nodiscord novoice", suffix: "-nodiscord", output: "AsyncAO-nodiscord-x86_64.AppImage" }
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
- name: Install SDL2 + libwebp + libavif dev packages + AppImage tooling
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
libsdl2-dev libsdl2-ttf-dev libwebp-dev libavif-dev libopus-dev libopusfile-dev cmake ninja-build pkg-config \
patchelf desktop-file-utils
- name: Build + install SDL Mixer X (crossfade + gapless loop points)
run: |
sudo bash scripts/build-sdl-mixer-x.sh /usr/local
echo "CGO_CFLAGS=-I/usr/local/include $(pkg-config --cflags sdl2)" >> "$GITHUB_ENV"
echo "CGO_LDFLAGS=-L/usr/local/lib" >> "$GITHUB_ENV"
- name: Build the binary
run: |
export CGO_ENABLED=1
go build -tags "${{ matrix.variant.tags }}" -pgo=auto -trimpath -ldflags "-s -w" -o asyncao ./cmd/asyncao
- name: Package the AppImage
run: |
chmod +x scripts/build-appimage.sh
APPIMAGE_OUTPUT="${{ matrix.variant.output }}" scripts/build-appimage.sh ./asyncao
- uses: actions/upload-artifact@v4
with:
name: asyncao-linux-x86_64-AppImage${{ matrix.variant.suffix }}
path: dist/${{ matrix.variant.output }}