Skip to content

Merge branch 'main' into dependabot/npm_and_yarn/webs/production-depe… #611

Merge branch 'main' into dependabot/npm_and_yarn/webs/production-depe…

Merge branch 'main' into dependabot/npm_and_yarn/webs/production-depe… #611

Workflow file for this run

name: Build and Release Multi-Platform
on:
push:
tags:
- 'v*'
branches:
- '**'
paths-ignore:
# 文档文件(不包括 skill-sublinkpro,它会被嵌入到二进制文件中)
- '*.md'
- 'docs/**'
# AI 代理配置和私有文档
- '.agents/**'
- '.claude/**'
- '.codex/**'
- 'AGENTS.md'
- 'CLAUDE.md'
- 'GEMINI.md'
- 'CONTRIBUTING.md'
# 编辑器/IDE 配置
- '.vscode/**'
- '.idea/**'
- '.editorconfig'
# Git 配置
- '.gitignore'
- '.gitattributes'
# 许可证文件
- 'LICENSE'
- 'COPYING'
permissions:
contents: write
packages: write
jobs:
build-frontend:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v7
- name: Set up Node.js
uses: actions/setup-node@v7
with:
node-version: '24'
# cache: 'yarn' # Disabled to prevent using system Yarn v1 which conflicts with Corepack Yarn v4
- name: Enable Corepack
run: corepack enable
- name: Get yarn cache directory path
id: yarn-cache-dir-path
run: |
cd webs
echo "dir=$(yarn config get cacheFolder)" >> $GITHUB_OUTPUT
- name: Cache dependencies
uses: actions/cache@v6
id: yarn-cache
with:
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('webs/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- name: Install frontend dependencies
run: |
cd webs
yarn install --immutable
- name: Lint frontend
run: |
cd webs
yarn run lint
- name: Build frontend
run: |
cd webs
yarn run build
- name: Upload frontend artifacts
uses: actions/upload-artifact@v7
with:
name: frontend-dist
path: webs/dist/
retention-days: 1
backend-quality:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v7
- name: Set up Go
uses: actions/setup-go@v7
with:
go-version: '1.26.4'
cache: true
cache-dependency-path: go.sum
- name: Download Go modules
run: go mod download
- name: Run golangci-lint
uses: golangci/golangci-lint-action@v9
with:
version: v2.12.2
- name: Run Go tests
run: go test ./...
# 使用矩阵策略并发构建不同架构的二进制文件
build-go-binaries:
needs: [build-frontend, backend-quality]
runs-on: ubuntu-latest
strategy:
fail-fast: false # 允许其他架构继续构建,即使某个失败
matrix:
include:
- goos: linux
goarch: amd64
output: sublinkPro-linux-amd64
upx: true
- goos: linux
goarch: arm64
output: sublinkPro-linux-arm64
upx: true
- goos: linux
goarch: arm
goarm: 7
output: sublinkPro-linux-armv7
upx: true
- goos: linux
goarch: 386
output: sublinkPro-linux-x86
upx: true
- goos: windows
goarch: amd64
output: sublinkPro-windows-amd64.exe
upx: false
- goos: windows
goarch: 386
output: sublinkPro-windows-x86.exe
upx: false
- goos: darwin
goarch: amd64
output: sublinkPro-darwin-amd64
upx: false
- goos: darwin
goarch: arm64
output: sublinkPro-darwin-arm64
upx: false
steps:
- name: Checkout code
uses: actions/checkout@v7
- name: Set up Go
uses: actions/setup-go@v7
with:
go-version: '1.26.4'
cache: true
cache-dependency-path: go.sum
- name: Download frontend artifacts
uses: actions/download-artifact@v8
with:
name: frontend-dist
path: static/
- name: Write version to VERSION file
run: |
if [[ $GITHUB_REF == refs/tags/* ]]; then
TAG_NAME=${GITHUB_REF#refs/tags/}
else
TAG_NAME=$(git rev-parse --short HEAD)
fi
echo "$TAG_NAME" > VERSION
echo "Written version $TAG_NAME to VERSION file"
- name: Build Go binary for ${{ matrix.goos }}/${{ matrix.goarch }}
run: |
mkdir -p build
echo "Building ${{ matrix.output }} for ${{ matrix.goos }}/${{ matrix.goarch }}..."
if [ -n "${{ matrix.goarm }}" ]; then
export GOARM="${{ matrix.goarm }}"
echo "Using GOARM=${GOARM}"
fi
CGO_ENABLED=0 GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} \
go build -tags=prod -ldflags="-s -w" -o build/${{ matrix.output }} .
echo "Build completed. Binary size:"
ls -lh build/${{ matrix.output }}
- name: Compress binary with UPX
if: matrix.upx
run: |
# 安装 UPX
sudo apt-get update && sudo apt-get install -y upx
echo "=== Original binary size ==="
ls -lh build/${{ matrix.output }}
# 使用最佳压缩率压缩 Linux 二进制文件
upx --best --lzma build/${{ matrix.output }} || true
echo "=== Compressed binary size ==="
ls -lh build/${{ matrix.output }}
- name: Upload binary artifact
uses: actions/upload-artifact@v7
with:
name: binary-${{ matrix.goos }}-${{ matrix.goarch }}
path: build/${{ matrix.output }}
retention-days: 1
# 合并所有架构的二进制文件
merge-binaries:
needs: build-go-binaries
runs-on: ubuntu-latest
steps:
- name: Download all binary artifacts
uses: actions/download-artifact@v8
with:
pattern: binary-*
path: build/
merge-multiple: true
- name: Verify all binaries
run: |
echo "=== All binary files ==="
ls -lh build/
# 验证所有必需的二进制文件都存在
REQUIRED_FILES=(
"sublinkPro-linux-amd64"
"sublinkPro-linux-arm64"
"sublinkPro-linux-armv7"
"sublinkPro-linux-x86"
"sublinkPro-windows-amd64.exe"
"sublinkPro-windows-x86.exe"
"sublinkPro-darwin-amd64"
"sublinkPro-darwin-arm64"
)
MISSING=0
for file in "${REQUIRED_FILES[@]}"; do
if [ ! -f "build/$file" ]; then
echo "ERROR: Missing required binary: $file"
MISSING=1
else
echo "OK: $file exists"
fi
done
if [ $MISSING -eq 1 ]; then
echo "ERROR: Some required binaries are missing!"
exit 1
fi
echo "=== All binaries verified successfully ==="
- name: Upload merged binaries
uses: actions/upload-artifact@v7
with:
name: go-binaries
path: build/
retention-days: 1
release:
if: startsWith(github.ref, 'refs/tags/')
needs: merge-binaries
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Download binary artifacts
uses: actions/download-artifact@v8
with:
name: go-binaries
path: build/
- name: Generate changelog
id: changelog
run: |
CURRENT_TAG=${GITHUB_REF#refs/tags/}
PREVIOUS_TAG=$(git describe --tags --abbrev=0 HEAD~1 2>/dev/null || echo "")
echo "current_tag=$CURRENT_TAG" >> $GITHUB_OUTPUT
if [ -z "$PREVIOUS_TAG" ]; then
echo "## 🎉 首次发布" > changelog.md
echo "" >> changelog.md
echo "### 📝 所有提交:" >> changelog.md
git log --pretty=format:"- %s (%h)" >> changelog.md
else
echo "## 🚀 更新内容 ($PREVIOUS_TAG -> $CURRENT_TAG)" > changelog.md
echo "" >> changelog.md
echo "### 📝 提交记录:" >> changelog.md
git log --pretty=format:"- %s (%h)" $PREVIOUS_TAG..$CURRENT_TAG >> changelog.md
fi
echo "" >> changelog.md
echo "### 📦 发布文件:" >> changelog.md
echo "- \`sublinkPro-linux-amd64\` - Linux x64" >> changelog.md
echo "- \`sublinkPro-linux-arm64\` - Linux ARM64" >> changelog.md
echo "- \`sublinkPro-linux-armv7\` - Linux ARMv7 (32-bit)" >> changelog.md
echo "- \`sublinkPro-linux-x86\` - Linux x86 (32-bit)" >> changelog.md
echo "- \`sublinkPro-windows-amd64.exe\` - Windows x64" >> changelog.md
echo "- \`sublinkPro-windows-x86.exe\` - Windows x86 (32-bit)" >> changelog.md
echo "- \`sublinkPro-darwin-amd64\` - macOS x64" >> changelog.md
echo "- \`sublinkPro-darwin-arm64\` - macOS ARM64 (Apple Silicon)" >> changelog.md
- name: Create Release
uses: softprops/action-gh-release@v3
with:
tag_name: ${{ steps.changelog.outputs.current_tag }}
name: Release ${{ steps.changelog.outputs.current_tag }}
body_path: changelog.md
files: |
build/sublinkPro-linux-amd64
build/sublinkPro-linux-arm64
build/sublinkPro-linux-armv7
build/sublinkPro-linux-x86
build/sublinkPro-windows-amd64.exe
build/sublinkPro-windows-x86.exe
build/sublinkPro-darwin-amd64
build/sublinkPro-darwin-arm64
draft: false
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
build-docker:
needs: [build-frontend, merge-binaries]
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v7
- name: Download frontend artifacts
uses: actions/download-artifact@v8
with:
name: frontend-dist
path: static/
- name: Download binary artifacts
uses: actions/download-artifact@v8
with:
name: go-binaries
path: build/
- name: Set up QEMU
uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Log in to Docker Hub
uses: docker/login-action@v4
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and Push Multi-Arch Docker Image
run: |
if [[ $GITHUB_REF == refs/tags/* ]]; then
# 带 tag 的推送:使用 tag 版本号 + latest
TAG=${GITHUB_REF#refs/tags/}
docker buildx build --no-cache --pull --platform linux/amd64,linux/arm64,linux/arm/v7,linux/386 \
-f Dockerfile.ci \
-t zerodeng/sublink-pro:${TAG} \
-t zerodeng/sublink-pro:latest \
--push .
else
# 分支推送:dev 和 main 分支统一使用 dev 标签,其他分支使用分支名
BRANCH=${GITHUB_REF#refs/heads/}
if [[ "$BRANCH" == "dev" || "$BRANCH" == "main" ]]; then
DOCKER_TAG="dev"
else
# 将分支名中的 / 替换为 - 以兼容 Docker tag 格式
DOCKER_TAG=${BRANCH//\//-}
fi
docker buildx build --no-cache --pull --platform linux/amd64,linux/arm64,linux/arm/v7,linux/386 \
-f Dockerfile.ci \
-t zerodeng/sublink-pro:${DOCKER_TAG} \
--push .
fi