Skip to content

Merge pull request #91 from lloydzhou/feature/apt-aggregate #1166

Merge pull request #91 from lloydzhou/feature/apt-aggregate

Merge pull request #91 from lloydzhou/feature/apt-aggregate #1166

Workflow file for this run

name: CI
on:
push:
branches: ["**"]
tags: ["v*"]
pull_request:
workflow_dispatch:
jobs:
bash-agent:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install test dependencies
run: |
sudo apt-get update
sudo apt-get install -y ripgrep gawk locales
sudo locale-gen en_US.UTF-8
mkdir -p .ci-bin
cat > .ci-bin/awk <<'EOF'
#!/usr/bin/env bash
exec env LC_ALL=C LANG=C gawk "$@"
EOF
chmod +x .ci-bin/awk
echo "$PWD/.ci-bin" >> "$GITHUB_PATH"
- name: Build bash artifact
run: make build-bash
- name: Test dist/agent.sh
env:
LANG: en_US.UTF-8
LC_ALL: en_US.UTF-8
PYTHONUTF8: "1"
run: AGENT=./dist/agent.sh bash tests/test.sh
- name: Upload agent.sh
uses: actions/upload-artifact@v4
with:
name: agent-sh
path: dist/agent.sh
goagent:
strategy:
fail-fast: false
matrix:
include:
- runner: ubuntu-latest
goos: linux
goarch: amd64
suffix: linux-amd64
ext: ""
cc: gcc
- runner: ubuntu-latest
goos: linux
goarch: arm64
suffix: linux-arm64
ext: ""
cc: aarch64-linux-gnu-gcc
- runner: macos-14
goos: darwin
goarch: arm64
suffix: darwin-arm64
ext: ""
cc: cc
- runner: macos-14
goos: darwin
goarch: amd64
suffix: darwin-amd64
ext: ""
cc: cc
runs-on: ${{ matrix.runner }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version-file: go/go.mod
- name: Run Go tests (linux amd64 only)
if: matrix.goos == 'linux' && matrix.goarch == 'amd64'
run: make test-go
- name: Install cross linker (linux arm64)
if: matrix.goos == 'linux' && matrix.goarch == 'arm64'
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu
- name: Build goagent (linux, Ubuntu 20.04 container)
if: matrix.goos == 'linux'
run: |
docker run --rm -v /opt/hostedtoolcache:/opt/hostedtoolcache -v "$PWD":/github/workspace -w /github/workspace ubuntu:20.04 \
bash -euxo pipefail -c '
GO_BIN="$(ls -d /opt/hostedtoolcache/go/*/x64/bin | sort -V | tail -1)/go"
export PATH="$(dirname "$GO_BIN"):$PATH"
export GOCACHE="$PWD/go/.gocache" GOMODCACHE="$PWD/go/.gomodcache"
go version
apt-get update
apt-get install -y --no-install-recommends gcc make libc6-dev
mkdir -p dist
if [ "${{ matrix.goarch }}" = "arm64" ]; then
apt-get install -y --no-install-recommends gcc-aarch64-linux-gnu libc6-dev-arm64-cross
export CC=aarch64-linux-gnu-gcc
export CGO_ENABLED=1 GOOS=linux GOARCH=arm64
else
export CC=gcc
export CGO_ENABLED=1 GOOS=linux GOARCH=amd64
fi
go -C go build -ldflags="-s -w" -trimpath -o ../dist/goagent-${{ matrix.suffix }} ./cmd/goagent
'
- name: Build goagent (macOS)
if: matrix.goos == 'darwin'
run: |
mkdir -p dist
CGO_ENABLED=1 GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} CC=${{ matrix.cc }} \
go -C go build -ldflags="-s -w" -o ../dist/goagent-${{ matrix.suffix }}${{ matrix.ext }} ./cmd/goagent
- name: Upload goagent
uses: actions/upload-artifact@v4
with:
name: goagent-${{ matrix.suffix }}
path: dist/goagent-${{ matrix.suffix }}${{ matrix.ext }}
rustagent:
strategy:
fail-fast: false
matrix:
include:
- runner: ubuntu-latest
target: x86_64-unknown-linux-gnu
suffix: linux-amd64
bin: rustagent
ext: ""
- runner: ubuntu-latest
target: aarch64-unknown-linux-gnu
suffix: linux-arm64
bin: rustagent
ext: ""
- runner: macos-14
target: aarch64-apple-darwin
suffix: darwin-arm64
bin: rustagent
ext: ""
- runner: macos-14
target: x86_64-apple-darwin
suffix: darwin-amd64
bin: rustagent
ext: ""
runs-on: ${{ matrix.runner }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Check Rust code (linux only)
if: matrix.runner == 'ubuntu-latest' && matrix.target == 'x86_64-unknown-linux-gnu'
run: make test-rust
- name: Install cross linker (linux arm64 target)
if: matrix.runner == 'ubuntu-latest' && matrix.target == 'aarch64-unknown-linux-gnu'
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu
- name: Build rustagent (macOS)
if: matrix.runner == 'macos-14'
run: |
mkdir -p dist
cd rust && cargo build --release --target ${{ matrix.target }}
cp target/${{ matrix.target }}/release/${{ matrix.bin }} ../dist/rustagent-${{ matrix.suffix }}${{ matrix.ext }}
- name: Build rustagent (linux, Ubuntu 20.04 container)
if: matrix.runner == 'ubuntu-latest'
run: |
docker run --rm -v "$PWD":/github/workspace -w /github/workspace ubuntu:20.04 \
bash -euxo pipefail -c '
apt-get update
apt-get install -y --no-install-recommends curl ca-certificates build-essential pkg-config
if [ "${{ matrix.target }}" = "aarch64-unknown-linux-gnu" ]; then
apt-get install -y --no-install-recommends gcc-aarch64-linux-gnu libc6-dev-arm64-cross
fi
export RUSTUP_HOME=/usr/local/rustup CARGO_HOME=/usr/local/cargo
export PATH="$CARGO_HOME/bin:$PATH"
curl --proto "=https" --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain stable --target ${{ matrix.target }}
if [ "${{ matrix.target }}" = "aarch64-unknown-linux-gnu" ]; then
export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc
fi
mkdir -p dist
cd rust && cargo build --release --target ${{ matrix.target }}
cp target/${{ matrix.target }}/release/${{ matrix.bin }} ../dist/rustagent-${{ matrix.suffix }}${{ matrix.ext }}
'
- name: Upload rustagent
uses: actions/upload-artifact@v4
with:
name: rustagent-${{ matrix.suffix }}
path: dist/rustagent-${{ matrix.suffix }}${{ matrix.ext }}
webagent:
strategy:
fail-fast: false
matrix:
include:
- runner: ubuntu-latest
target: x86_64-unknown-linux-gnu
suffix: linux-amd64
bin: webagent
ext: ""
- runner: ubuntu-latest
target: aarch64-unknown-linux-gnu
suffix: linux-arm64
bin: webagent
ext: ""
- runner: macos-14
target: aarch64-apple-darwin
suffix: darwin-arm64
bin: webagent
ext: ""
- runner: macos-14
target: x86_64-apple-darwin
suffix: darwin-amd64
bin: webagent
ext: ""
runs-on: ${{ matrix.runner }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Install cross linker (linux arm64 target)
if: matrix.runner == 'ubuntu-latest' && matrix.target == 'aarch64-unknown-linux-gnu'
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu
- name: Build webagent (macOS)
if: matrix.runner == 'macos-14'
run: |
mkdir -p dist
cd webagent && cargo build --release --target ${{ matrix.target }}
cp target/${{ matrix.target }}/release/${{ matrix.bin }} ../dist/webagent-${{ matrix.suffix }}${{ matrix.ext }}
- name: Build webagent (linux, Ubuntu 20.04 container)
if: matrix.runner == 'ubuntu-latest'
run: |
docker run --rm -v "$PWD":/github/workspace -w /github/workspace ubuntu:20.04 \
bash -euxo pipefail -c '
apt-get update
apt-get install -y --no-install-recommends curl ca-certificates build-essential pkg-config
if [ "${{ matrix.target }}" = "aarch64-unknown-linux-gnu" ]; then
apt-get install -y --no-install-recommends gcc-aarch64-linux-gnu libc6-dev-arm64-cross
fi
export RUSTUP_HOME=/usr/local/rustup CARGO_HOME=/usr/local/cargo
export PATH="$CARGO_HOME/bin:$PATH"
curl --proto "=https" --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --default-toolchain stable --target ${{ matrix.target }}
if [ "${{ matrix.target }}" = "aarch64-unknown-linux-gnu" ]; then
export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc
fi
mkdir -p dist
cd webagent && cargo build --release --target ${{ matrix.target }}
cp target/${{ matrix.target }}/release/${{ matrix.bin }} ../dist/webagent-${{ matrix.suffix }}${{ matrix.ext }}
'
- name: Upload webagent
uses: actions/upload-artifact@v4
with:
name: webagent-${{ matrix.suffix }}
path: dist/webagent-${{ matrix.suffix }}${{ matrix.ext }}
cagent:
strategy:
fail-fast: false
matrix:
include:
- runner: ubuntu-latest
suffix: linux-amd64
cc: gcc
- runner: ubuntu-24.04-arm
suffix: linux-arm64
cc: gcc
- runner: macos-14
suffix: darwin-arm64
cc: cc
- runner: macos-14
suffix: darwin-amd64
cc: cc
runs-on: ${{ matrix.runner }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install build dependencies (linux)
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y ripgrep gcc-aarch64-linux-gnu
- name: Build cagent (linux, Ubuntu 20.04 container)
if: runner.os == 'Linux'
run: |
docker run --rm -v "$PWD":/github/workspace -w /github/workspace ubuntu:20.04 \
bash -euxo pipefail -c '
apt-get update
apt-get install -y --no-install-recommends gcc make xxd libc6-dev libcurl4-openssl-dev pkg-config
mkdir -p dist
make -C c CC=gcc
mv dist/cagent dist/cagent-${{ matrix.suffix }}
'
- name: Install build dependencies (macOS)
if: runner.os == 'macOS'
run: brew install curl
- name: Build cagent (macOS)
if: runner.os == 'macOS'
run: |
mkdir -p dist
if [ "${{ matrix.suffix }}" = "darwin-amd64" ]; then
make -C c CC=${{ matrix.cc }} 'CFLAGS=-std=c11 -Wall -Wextra -Wno-unused-parameter -O2 -D_GNU_SOURCE -arch x86_64 -Ivendor/linenoise' 'LDFLAGS=-lcurl -arch x86_64'
else
make -C c CC=${{ matrix.cc }}
fi
mv dist/cagent dist/cagent-${{ matrix.suffix }}
- name: Test cagent (linux amd64 only)
if: matrix.suffix == 'linux-amd64'
run: |
sudo cp dist/cagent-linux-amd64 dist/cagent
AGENT=./dist/cagent bash tests/test.sh
- name: Upload cagent
uses: actions/upload-artifact@v4
with:
name: cagent-${{ matrix.suffix }}
path: dist/cagent-${{ matrix.suffix }}
tcode:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Copy tcode
run: |
mkdir -p dist
cp scripts/tcode dist/tcode
chmod +x dist/tcode
- name: Upload tcode
uses: actions/upload-artifact@v4
with:
name: tcode
path: dist/tcode
deb-package:
needs: [bash-agent, goagent, rustagent, cagent, tcode, webagent]
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
path: dist
merge-multiple: true
- name: Install Debian packaging tools
run: |
sudo apt-get update
sudo apt-get install -y binutils binutils-aarch64-linux-gnu
- name: Build Debian packages
id: build-deb
run: |
if [[ "$GITHUB_REF" == refs/tags/v* ]]; then
version="${GITHUB_REF_NAME#v}"
else
version="0.0.0+git${GITHUB_SHA:0:7}"
fi
make build-deb VERSION="$version"
echo "version=$version" >> "$GITHUB_OUTPUT"
- name: Verify Debian packages
env:
DEB_VERSION: ${{ steps.build-deb.outputs.version }}
run: |
amd64_deb="dist/bash-agent_${DEB_VERSION}_amd64.deb"
arm64_deb="dist/bash-agent_${DEB_VERSION}_arm64.deb"
test "$(dpkg-deb -f "$amd64_deb" Architecture)" = amd64
test "$(dpkg-deb -f "$arm64_deb" Architecture)" = arm64
sudo apt-get install -y "./$amd64_deb"
for command_name in bash-agent goagent rustagent cagent webagent tcode; do
test -x "/usr/bin/$command_name"
done
- name: Verify GLIBC_2.31 baseline (release gate)
run: |
set -euo pipefail
GLIBC_MIN=2.31
check() {
local file="$1" objdump="$2"
local max_ver
max_ver="$($objdump -T "$file" | grep -oE 'GLIBC_[0-9]+\.[0-9]+(\.[0-9]+)?' | sed 's/^GLIBC_//' | sort -V | tail -1)"
if [[ -z "$max_ver" ]]; then
echo "错误:$file 未找到任何 GLIBC 符号引用" >&2
exit 1
fi
if [[ "$(printf '%s\n%s\n' "$max_ver" "$GLIBC_MIN" | sort -V | tail -1)" != "$GLIBC_MIN" ]]; then
echo "错误:$file 引用了高于 $GLIBC_MIN 的 GLIBC 符号(最高 GLIBC_$max_ver)" >&2
exit 1
fi
echo "通过:$file 最高 GLIBC_$max_ver"
}
for f in dist/goagent-linux-amd64 dist/rustagent-linux-amd64 dist/cagent-linux-amd64 dist/webagent-linux-amd64; do
check "$f" objdump
done
for f in dist/goagent-linux-arm64 dist/rustagent-linux-arm64 dist/cagent-linux-arm64 dist/webagent-linux-arm64; do
check "$f" aarch64-linux-gnu-objdump
done
- name: Upload Debian packages
uses: actions/upload-artifact@v4
with:
name: debian-packages
path: dist/bash-agent_*.deb
release:
if: startsWith(github.ref, 'refs/tags/v')
needs: [bash-agent, goagent, rustagent, cagent, tcode, webagent, deb-package]
runs-on: ubuntu-latest
permissions:
contents: write
pages: write
id-token: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: dist
merge-multiple: true
- name: Show artifacts
run: ls -lh dist
- name: Generate checksums
env:
ARCHIVE_URL: https://github.com/${{ github.repository }}/archive/refs/tags/${{ github.ref_name }}.tar.gz
run: |
curl -fsSL "$ARCHIVE_URL" -o "dist/${{ github.ref_name }}.tar.gz"
(
cd dist
sha256sum \
"${{ github.ref_name }}.tar.gz" \
agent.sh \
goagent-linux-amd64 \
goagent-linux-arm64 \
goagent-darwin-amd64 \
goagent-darwin-arm64 \
rustagent-linux-amd64 \
rustagent-linux-arm64 \
rustagent-darwin-amd64 \
rustagent-darwin-arm64 \
cagent-linux-amd64 \
cagent-linux-arm64 \
cagent-darwin-amd64 \
cagent-darwin-arm64 \
webagent-linux-amd64 \
webagent-linux-arm64 \
webagent-darwin-amd64 \
webagent-darwin-arm64 \
tcode \
bash-agent_*_amd64.deb \
bash-agent_*_arm64.deb > checksums.txt
)
- name: Generate release notes from CHANGELOG
run: |
curl -fsSL "https://raw.githubusercontent.com/${{ github.repository }}/${{ github.ref_name }}/CHANGELOG.md" -o CHANGELOG.md
awk -v ver="${{ github.ref_name }}" '
sub(/^v/, "", ver)
$0 ~ "^## \\[" ver "\\]" { found=1; next }
found && $0 ~ /^## / { exit }
found { print }
' CHANGELOG.md | sed '/^---$/d' > release-notes.md
test -s release-notes.md
echo "release-notes.md 内容:"
head -5 release-notes.md
- name: Publish release assets
uses: softprops/action-gh-release@v2
with:
body_path: release-notes.md
files: |
dist/checksums.txt
dist/agent.sh
dist/goagent-linux-amd64
dist/goagent-linux-arm64
dist/goagent-darwin-amd64
dist/goagent-darwin-arm64
dist/rustagent-linux-amd64
dist/rustagent-linux-arm64
dist/rustagent-darwin-amd64
dist/rustagent-darwin-arm64
dist/cagent-linux-amd64
dist/cagent-linux-arm64
dist/cagent-darwin-amd64
dist/cagent-darwin-arm64
dist/webagent-linux-amd64
dist/webagent-linux-arm64
dist/webagent-darwin-amd64
dist/webagent-darwin-arm64
dist/tcode
dist/bash-agent_*_amd64.deb
dist/bash-agent_*_arm64.deb
- name: Fetch mcpc/oapi debs for aggregate apt repo
run: bash scripts/apt/fetch-debs.sh dist lloydzhou/mcpc lloydzhou/oapi
- name: Build APT repository and site
env:
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
run: |
set -euo pipefail
sudo apt-get update -qq
sudo apt-get install -y -qq gnupg 2>&1 | tail -1
bash scripts/apt/build-apt-repo.sh "${{ github.ref_name }}" dist apt-repo
# 组装 Pages 站点根:官网(site/)+ apt 仓库(debian/)+ install.sh
cp -r site/. apt-repo/
cp scripts/install-apt.sh apt-repo/install.sh
find apt-repo -maxdepth 2 | sort
- name: Configure Pages
uses: actions/configure-pages@v5
- name: Upload Pages artifact
uses: actions/upload-pages-artifact@v3
with:
path: apt-repo
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4