name: Build, Push and Release
on:
workflow_dispatch: inputs:
debug_mode:
description: 'Enable debug mode (no push to registry, save artifacts)'
required: false
default: false
type: boolean
use_china_mirror:
description: 'Use China mirror for faster downloads (for China-based runners)'
required: false
default: false
type: boolean
alpine_mirror:
description: 'Alpine Linux mirror'
required: false
default: 'mirrors.aliyun.com'
type: choice
options:
- mirrors.aliyun.com
- mirrors.tuna.tsinghua.edu.cn
- mirrors.ustc.edu.cn
rust_mirror:
description: 'Rust Crates mirror'
required: false
default: 'tuna'
type: choice
options:
- tuna
- ustc
env:
REGISTRY: ghcr.io
BINARY_NAME: ${{ github.event.repository.name }}
jobs:
build-and-push:
name: Build Static Binary and Push to GHCR
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up flags
id: flags
run: |
# 设置 debug_mode 标志
if [ "${{ inputs.debug_mode }}" = "true" ]; then
echo "debug_mode=true" >> $GITHUB_OUTPUT
else
echo "debug_mode=false" >> $GITHUB_OUTPUT
fi
# 检测是否是 main 分支
if [ "${{ github.ref }}" = "refs/heads/main" ]; then
echo "is_main=true" >> $GITHUB_OUTPUT
else
echo "is_main=false" >> $GITHUB_OUTPUT
fi
echo "debug_mode: ${{ steps.flags.outputs.debug_mode }}"
echo "is_main: ${{ steps.flags.outputs.is_main }}"
- name: Set up lowercase repository name
id: repo
run: |
# 将仓库名称转换为小写
REPO_LOWER=$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]')
echo "repo_lower=$REPO_LOWER" >> $GITHUB_OUTPUT
echo "Using repository: $REPO_LOWER"
- name: Debug Information
run: |
echo "🔧 Debug Mode: ${{ inputs.debug_mode }}"
echo "🌐 China Mirror: ${{ inputs.use_china_mirror }}"
echo "📡 Alpine Mirror: ${{ inputs.alpine_mirror }}"
echo "⚙️ Rust Mirror: ${{ inputs.rust_mirror }}"
echo "🏷️ Trigger Event: ${{ github.event_name }}"
echo "🔖 Ref: ${{ github.ref }}"
echo "📝 SHA: ${{ github.sha }}"
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry (skip in debug mode)
if: ${{ !inputs.debug_mode }}
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract Docker image metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ steps.repo.outputs.repo_lower }}
tags: |
type=ref,event=tag
type=raw,value=scratch,enable=${{ steps.flags.outputs.is_main == 'true' }}
type=raw,value=latest,enable=${{ steps.flags.outputs.is_main == 'true' }}
type=raw,value=debug-${{ github.sha }},enable=${{ steps.flags.outputs.debug_mode == 'true' }}
type=sha,prefix=git-
- name: Build Docker image
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64
push: ${{ !inputs.debug_mode }} tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
target: runtime
build-args: |
USE_CHINA_MIRROR=${{ inputs.use_china_mirror }}
ALPINE_MIRROR=${{ inputs.alpine_mirror }}
RUST_MIRROR=${{ inputs.rust_mirror }}
cache-from: type=gha
cache-to: type=gha,mode=max
outputs: ${{ inputs.debug_mode && 'type=docker,dest=/tmp/image.tar' || '' }}
- name: Save image locally (debug mode)
if: ${{ inputs.debug_mode }}
run: |
echo "🔧 Debug mode: Saving image to workspace..."
mkdir -p /tmp/debug-artifacts
cp /tmp/image.tar /tmp/debug-artifacts/code_packager-debug.tar
echo "Image saved to /tmp/debug-artifacts/"
- name: Upload debug artifacts (debug mode)
if: ${{ inputs.debug_mode }}
uses: actions/upload-artifact@v4
with:
name: docker-image-debug
path: /tmp/debug-artifacts/
retention-days: 1
- name: Image inspection (debug mode)
if: ${{ inputs.debug_mode }}
run: |
echo "🔍 Inspecting built image..."
docker load -i /tmp/image.tar
docker images
echo "=== Image details ==="
IMAGE_TAG="${{ env.REGISTRY }}/${{ steps.repo.outputs.repo_lower }}:debug-${{ github.sha }}"
if docker image inspect "$IMAGE_TAG" >/dev/null 2>&1; then
docker image inspect "$IMAGE_TAG" | jq '.[0] | {Size: .Size, Architecture: .Architecture, Os: .Os}'
else
echo "⚠️ Debug image not found for inspection, listing all images:"
docker images
fi
- name: Test image (debug mode)
if: ${{ inputs.debug_mode }}
run: |
echo "🧪 Testing built image..."
IMAGE_TAG="${{ env.REGISTRY }}/${{ steps.repo.outputs.repo_lower }}:debug-${{ github.sha }}"
if docker image inspect "$IMAGE_TAG" >/dev/null 2>&1; then
docker run --rm "$IMAGE_TAG" --version || \
docker run --rm "$IMAGE_TAG" --help || \
echo "Image runs successfully"
echo "✅ Image test completed"
else
echo "❌ Debug image not found for testing"
fi
- name: Extract binary from Docker image
id: extract-binary
run: |
# 创建临时目录
mkdir -p release-binaries
# 使用第一个标签来提取二进制文件
FIRST_TAG=$(echo "${{ steps.meta.outputs.tags }}" | cut -d',' -f1)
echo "Using tag for extraction: $FIRST_TAG"
# 从刚构建的镜像中提取二进制文件 - 使用正确的路径 /app/code_packager
docker create --name extract-binary-container $FIRST_TAG
docker cp extract-binary-container:/app/code_packager release-binaries/${{ env.BINARY_NAME }}
docker rm -f extract-binary-container
# 使二进制文件可执行
chmod +x release-binaries/${{ env.BINARY_NAME }}
# 获取二进制文件信息
echo "binary_size=$(du -h release-binaries/${{ env.BINARY_NAME }} | cut -f1)" >> $GITHUB_OUTPUT
echo "binary_path=release-binaries/${{ env.BINARY_NAME }}" >> $GITHUB_OUTPUT
# 显示文件信息
echo "📄 File information:"
file release-binaries/${{ env.BINARY_NAME }}
echo "📊 File details:"
ls -la release-binaries/${{ env.BINARY_NAME }}
echo "🔍 Binary inspection:"
strings release-binaries/${{ env.BINARY_NAME }} | head -5
- name: Test extracted binary
run: |
echo "🧪 Testing extracted binary..."
./release-binaries/${{ env.BINARY_NAME }} --version || \
./release-binaries/${{ env.BINARY_NAME }} --help || \
echo "Binary executed successfully"
- name: Upload binary artifact
uses: actions/upload-artifact@v4
with:
name: ${{ env.BINARY_NAME }}-binary
path: release-binaries/${{ env.BINARY_NAME }}
retention-days: 1
- name: Build completion report (production mode)
if: ${{ !inputs.debug_mode }}
run: |
echo "🎉 Build Completed Successfully"
echo "==============================="
echo "📦 Image: ${{ env.REGISTRY }}/${{ steps.repo.outputs.repo_lower }}"
echo "🏷️ Tags: ${{ steps.meta.outputs.tags }}"
echo "🏗️ Architecture: x86_64 (amd64)"
echo "📐 Platform: linux/amd64"
echo "🔧 Build Type: Static musl binary on scratch"
echo "📦 Binary: ${{ steps.extract-binary.outputs.binary_path }} (${{ steps.extract-binary.outputs.binary_size }})"
echo "🌐 China Mirror: ${{ inputs.use_china_mirror }}"
echo "📡 Alpine Mirror: ${{ inputs.alpine_mirror }}"
echo "⚙️ Rust Mirror: ${{ inputs.rust_mirror }}"
- name: Debug mode completion message
if: ${{ inputs.debug_mode }}
run: |
echo "🔧 Debug Mode Completed Successfully!"
echo "===================================="
echo "📦 Image built but NOT pushed to registry"
echo "🏷️ Debug tag: debug-${{ github.sha }}"
echo "💾 Artifacts saved for inspection"
echo "🔍 Image inspected and tested locally"
echo "🔄 To publish, re-run without debug mode"
create-release:
name: Create GitHub Release
runs-on: ubuntu-latest
needs: build-and-push
permissions:
contents: write
if: startsWith(github.ref, 'refs/tags/v') && !inputs.debug_mode
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up lowercase repository name
id: repo
run: |
# 将仓库名称转换为小写
REPO_LOWER=$(echo "${{ github.repository }}" | tr '[:upper:]' '[:lower:]')
echo "repo_lower=$REPO_LOWER" >> $GITHUB_OUTPUT
- name: Download binary artifact
uses: actions/download-artifact@v4
with:
name: ${{ env.BINARY_NAME }}-binary
path: release-binaries
- name: Create checksums
run: |
cd release-binaries
sha256sum ${{ env.BINARY_NAME }} > ${{ env.BINARY_NAME }}.sha256
sha512sum ${{ env.BINARY_NAME }} > ${{ env.BINARY_NAME }}.sha512
echo "Checksums created:"
cat ${{ env.BINARY_NAME }}.sha256
cat ${{ env.BINARY_NAME }}.sha512
- name: Create GitHub Release
uses: softprops/action-gh-release@v1
with:
files: |
release-binaries/${{ env.BINARY_NAME }}
release-binaries/${{ env.BINARY_NAME }}.sha256
release-binaries/${{ env.BINARY_NAME }}.sha512
generate_release_notes: true
draft: false
prerelease: ${{ contains(github.ref, '-alpha') || contains(github.ref, '-beta') || contains(github.ref, '-rc') }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Release completion report
run: |
echo "🚀 Release Published Successfully"
echo "================================"
echo "📦 Binary: ${{ env.BINARY_NAME }}"
echo "📁 Files uploaded:"
echo " - ${{ env.BINARY_NAME }} (executable)"
echo " - ${{ env.BINARY_NAME }}.sha256 (SHA256 checksum)"
echo " - ${{ env.BINARY_NAME }}.sha512 (SHA512 checksum)"
echo "🏷️ Tag: ${GITHUB_REF#refs/tags/}"