chore: release v0.1.1 #4
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build and Release RunPanel | ||
| on: | ||
| push: | ||
| tags: | ||
| - 'v*' | ||
| release: | ||
| types: [published] | ||
| workflow_dispatch: | ||
| inputs: | ||
| version: | ||
| description: '版本号 (如: v1.0.0)' | ||
| required: true | ||
| default: 'v1.0.0' | ||
| dry_run: | ||
| description: '仅构建与产出制品,不创建GitHub Release(默认 true)' | ||
| required: false | ||
| default: 'true' | ||
| env: | ||
| REGISTRY: ghcr.io | ||
| IMAGE_NAME: ${{ github.repository }} | ||
| jobs: | ||
| # 检查前端文件是否存在 | ||
| check-frontend: | ||
| runs-on: ubuntu-latest | ||
| outputs: | ||
| has-frontend: ${{ steps.check.outputs.has-frontend }} | ||
| frontend-version: ${{ steps.check.outputs.frontend-version }} | ||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 | ||
| - name: Ensure jq is available | ||
| run: | | ||
| if ! command -v jq >/dev/null 2>&1; then | ||
| sudo apt-get update -y | ||
| sudo apt-get install -y jq | ||
| fi | ||
| - name: Check frontend files | ||
| id: check | ||
| run: | | ||
| if [ -d "web/dist" ] && [ -f "web/dist/index.html" ]; then | ||
| echo "has-frontend=true" >> $GITHUB_OUTPUT | ||
| echo "✅ 检测到前端文件" | ||
| # 获取前端版本信息 | ||
| if [ -f "web/dist/version.json" ]; then | ||
| frontend_version=$(cat web/dist/version.json | jq -r '.version' 2>/dev/null || echo "unknown") | ||
| echo "frontend-version=$frontend_version" >> $GITHUB_OUTPUT | ||
| echo "前端版本: $frontend_version" | ||
| else | ||
| echo "frontend-version=unknown" >> $GITHUB_OUTPUT | ||
| fi | ||
| # 显示前端文件统计 | ||
| echo "前端文件数量: $(find web/dist -type f | wc -l)" | ||
| echo "前端文件大小: $(du -sh web/dist | cut -f1)" | ||
| else | ||
| echo "has-frontend=false" >> $GITHUB_OUTPUT | ||
| echo "❌ 未找到前端文件,请先运行 scripts/build-frontend.sh" | ||
| exit 1 | ||
| fi | ||
| # 构建多架构二进制文件 | ||
| build: | ||
| needs: check-frontend | ||
| runs-on: ubuntu-latest | ||
| strategy: | ||
| matrix: | ||
| include: | ||
| - os: linux | ||
| arch: amd64 | ||
| goos: linux | ||
| goarch: amd64 | ||
| - os: linux | ||
| arch: arm64 | ||
| goos: linux | ||
| goarch: arm64 | ||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 | ||
| - name: Verify build context | ||
| run: | | ||
| echo "工作目录: $(pwd)" | ||
| echo "列出关键目录:" | ||
| ls -la | ||
| echo "--- cmd 目录 ---" | ||
| ls -la cmd || true | ||
| echo "--- cmd/paneld 目录 ---" | ||
| ls -la cmd/paneld || true | ||
| - name: Set up Go | ||
| uses: actions/setup-go@v4 | ||
| with: | ||
| go-version: '1.24.x' | ||
| - name: Get version | ||
| id: version | ||
| run: | | ||
| if [ "${{ github.event_name }}" = "release" ]; then | ||
| VERSION="${{ github.event.release.tag_name }}" | ||
| elif [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | ||
| VERSION="${{ github.event.inputs.version }}" | ||
| elif [ "${{ github.ref_type }}" = "tag" ]; then | ||
| VERSION=${GITHUB_REF#refs/tags/} | ||
| else | ||
| VERSION="v$(cat VERSION)" | ||
| fi | ||
| echo "version=$VERSION" >> $GITHUB_OUTPUT | ||
| echo "VERSION=$VERSION" >> $GITHUB_ENV | ||
| echo "构建版本: $VERSION" | ||
| - name: Set build info | ||
| id: build-info | ||
| run: | | ||
| BUILD_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ") | ||
| GIT_COMMIT=$(git rev-parse --short HEAD) | ||
| GIT_TAG=$(git describe --tags --exact-match 2>/dev/null || echo "") | ||
| echo "build-time=$BUILD_TIME" >> $GITHUB_OUTPUT | ||
| echo "git-commit=$GIT_COMMIT" >> $GITHUB_OUTPUT | ||
| echo "git-tag=$GIT_TAG" >> $GITHUB_OUTPUT | ||
| echo "BUILD_TIME=$BUILD_TIME" >> $GITHUB_ENV | ||
| echo "GIT_COMMIT=$GIT_COMMIT" >> $GITHUB_ENV | ||
| echo "GIT_TAG=$GIT_TAG" >> $GITHUB_ENV | ||
| - name: Resolve build package | ||
| id: pkg | ||
| run: | | ||
| set -e | ||
| PKG="" | ||
| if [ -d cmd/paneld ]; then | ||
| PKG="./cmd/paneld" | ||
| elif [ -d cmd/panel ]; then | ||
| PKG="./cmd/panel" | ||
| else | ||
| echo "自动探测 main 包..." | ||
| # 输出第一个 main 包目录 | ||
| PKG=$(go list -f '{{if eq .Name "main"}}{{.Dir}}{{end}}' ./... | grep -v "/internal/" | head -n1) | ||
| fi | ||
| if [ -z "$PKG" ]; then | ||
| echo "::error::未能找到可构建的 main 包,请确认仓库包含主程序入口(如 cmd/paneld)。" | ||
| exit 1 | ||
| fi | ||
| echo "build-pkg=$PKG" >> $GITHUB_OUTPUT | ||
| echo "构建包: $PKG" | ||
| - name: Prepare embedded frontend (copy web/dist to internal/frontend/dist) | ||
| run: | | ||
| rm -rf internal/frontend/dist | ||
| mkdir -p internal/frontend/dist | ||
| cp -r web/dist/* internal/frontend/dist/ | ||
| # embed version info for runtime display (optional) | ||
| cat > internal/frontend/dist/version.json << EOF | ||
| { | ||
| "version": "${{ env.VERSION }}", | ||
| "buildTime": "${{ env.BUILD_TIME }}", | ||
| "gitCommit": "${{ env.GIT_COMMIT }}", | ||
| "gitTag": "${{ env.GIT_TAG }}", | ||
| "buildType": "embedded", | ||
| "devMode": false | ||
| } | ||
| EOF | ||
| echo "Embedded files count: $(find internal/frontend/dist -type f | wc -l)" | ||
| - name: Build binary | ||
| run: | | ||
| # 设置构建参数 | ||
| LDFLAGS="-s -w" | ||
| LDFLAGS="$LDFLAGS -X 'github.com/Run-Panel/RunPanel/internal/version.Version=${{ env.VERSION }}'" | ||
| LDFLAGS="$LDFLAGS -X 'github.com/Run-Panel/RunPanel/internal/version.BuildTime=${{ env.BUILD_TIME }}'" | ||
| LDFLAGS="$LDFLAGS -X 'github.com/Run-Panel/RunPanel/internal/version.GitCommit=${{ env.GIT_COMMIT }}'" | ||
| LDFLAGS="$LDFLAGS -X 'github.com/Run-Panel/RunPanel/internal/version.GitTag=${{ env.GIT_TAG }}'" | ||
| echo "构建 ${{ matrix.os }}-${{ matrix.arch }} 版本..." | ||
| # 创建输出目录 | ||
| mkdir -p dist/runpanel-embedded-${{ matrix.os }}-${{ matrix.arch }} | ||
| # 编译二进制文件 | ||
| CGO_ENABLED=0 GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} \ | ||
| go build -ldflags "$LDFLAGS" \ | ||
| -o dist/runpanel-embedded-${{ matrix.os }}-${{ matrix.arch }}/runpanel \ | ||
| "${{ steps.pkg.outputs.build-pkg }}" | ||
| # 设置执行权限 | ||
| chmod +x dist/runpanel-embedded-${{ matrix.os }}-${{ matrix.arch }}/runpanel | ||
| - name: Create release package | ||
| run: | | ||
| cd dist/runpanel-embedded-${{ matrix.os }}-${{ matrix.arch }} | ||
| # 复制配置文件 | ||
| cp -r ../../configs . | ||
| # 创建启动脚本 | ||
| cat > start.sh << 'EOF' | ||
| #!/bin/bash | ||
| # RunPanel 嵌入式版本启动脚本 | ||
| set -e | ||
| SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" | ||
| BINARY_PATH="$SCRIPT_DIR/runpanel" | ||
| CONFIG_PATH="$SCRIPT_DIR/configs/config.yaml" | ||
| echo "[INFO] 启动 RunPanel (嵌入式版本)" | ||
| echo "=================================" | ||
| echo "二进制文件: $BINARY_PATH" | ||
| echo "配置文件: $CONFIG_PATH" | ||
| echo "启动时间: $(date)" | ||
| echo "" | ||
| # 检查文件是否存在 | ||
| if [ ! -f "$BINARY_PATH" ]; then | ||
| echo "[ERROR] 二进制文件不存在: $BINARY_PATH" | ||
| exit 1 | ||
| fi | ||
| if [ ! -f "$CONFIG_PATH" ]; then | ||
| echo "[ERROR] 配置文件不存在: $CONFIG_PATH" | ||
| exit 1 | ||
| fi | ||
| # 创建必要目录 | ||
| mkdir -p "$SCRIPT_DIR/data" | ||
| mkdir -p "$SCRIPT_DIR/logs" | ||
| # 启动应用 | ||
| echo "[INFO] 启动应用..." | ||
| exec "$BINARY_PATH" -config "$CONFIG_PATH" "$@" | ||
| EOF | ||
| chmod +x start.sh | ||
| # 创建README | ||
| cat > README.md << EOF | ||
| # RunPanel 嵌入式版本 | ||
| 版本: ${{ env.VERSION }} | ||
| 构建时间: ${{ env.BUILD_TIME }} | ||
| 平台: ${{ matrix.os }}-${{ matrix.arch }} | ||
| Git提交: ${{ env.GIT_COMMIT }} | ||
| ## 文件说明 | ||
| - \`runpanel\` - 主程序二进制文件(已嵌入前端) | ||
| - \`start.sh\` - 启动脚本 | ||
| - \`configs/\` - 配置文件目录 | ||
| ## 启动方式 | ||
| ### 使用启动脚本(推荐) | ||
| \`\`\`bash | ||
| ./start.sh | ||
| \`\`\` | ||
| ### 直接运行 | ||
| \`\`\`bash | ||
| ./runpanel -config configs/config.yaml | ||
| \`\`\` | ||
| ## 访问地址 | ||
| - 前端界面: http://localhost:8081 | ||
| - API接口: http://localhost:8081/api | ||
| ## 特性 | ||
| EOF | ||
| # 创建构建信息 | ||
| cat > build-info.json << EOF | ||
| { | ||
| "version": "${{ env.VERSION }}", | ||
| "buildTime": "${{ env.BUILD_TIME }}", | ||
| "gitCommit": "${{ env.GIT_COMMIT }}", | ||
| "gitTag": "${{ env.GIT_TAG }}", | ||
| "platform": { | ||
| "os": "${{ matrix.os }}", | ||
| "arch": "${{ matrix.arch }}" | ||
| }, | ||
| "buildType": "embedded", | ||
| "frontendIncluded": true, | ||
| "frontendVersion": "${{ needs.check-frontend.outputs.frontend-version }}" | ||
| } | ||
| EOF | ||
| - name: Create tarball | ||
| run: | | ||
| cd dist | ||
| tar -czf runpanel-embedded-${{ matrix.os }}-${{ matrix.arch }}.tar.gz \ | ||
| runpanel-embedded-${{ matrix.os }}-${{ matrix.arch }}/ | ||
| # 验证压缩包 | ||
| echo "压缩包大小: $(ls -lh runpanel-embedded-${{ matrix.os }}-${{ matrix.arch }}.tar.gz | awk '{print $5}')" | ||
| - name: Upload artifacts | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: runpanel-embedded-${{ matrix.os }}-${{ matrix.arch }} | ||
| path: dist/runpanel-embedded-${{ matrix.os }}-${{ matrix.arch }}.tar.gz | ||
| retention-days: 30 | ||
| # 创建GitHub Release | ||
| release: | ||
| needs: [check-frontend, build] | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: write | ||
| outputs: | ||
| version: ${{ steps.version.outputs.version }} | ||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 | ||
| - name: Get version | ||
| id: version | ||
| run: | | ||
| if [ "${{ github.event_name }}" = "release" ]; then | ||
| VERSION="${{ github.event.release.tag_name }}" | ||
| elif [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | ||
| VERSION="${{ github.event.inputs.version }}" | ||
| elif [ "${{ github.ref_type }}" = "tag" ]; then | ||
| VERSION=${GITHUB_REF#refs/tags/} | ||
| else | ||
| VERSION="v$(cat VERSION)" | ||
| fi | ||
| echo "version=$VERSION" >> $GITHUB_OUTPUT | ||
| echo "VERSION=$VERSION" >> $GITHUB_ENV | ||
| - name: Download all artifacts | ||
| uses: actions/download-artifact@v4 | ||
| with: | ||
| path: artifacts/ | ||
| # 合并多个制品到同一目录,便于后续处理 | ||
| merge-multiple: true | ||
| - name: Prepare release files | ||
| run: | | ||
| mkdir -p release-files | ||
| # 移动所有构建文件到release目录 | ||
| find artifacts -name "*.tar.gz" -exec mv {} release-files/ \; | ||
| # 生成checksums | ||
| cd release-files | ||
| sha256sum *.tar.gz > checksums.txt | ||
| echo "Release 文件:" | ||
| ls -la | ||
| - name: Generate release notes | ||
| id: release-notes | ||
| run: | | ||
| cat > release-notes.md << EOF | ||
| ## RunPanel ${{ env.VERSION }} 发布说明 | ||
| ### 📦 发布文件 | ||
| | 文件名 | 平台 | 描述 | | ||
| |--------|------|------| | ||
| | \`runpanel-embedded-linux-amd64.tar.gz\` | Linux x86_64 | 适用于大多数Linux服务器 | | ||
| | \`runpanel-embedded-linux-arm64.tar.gz\` | Linux ARM64 | 适用于ARM64服务器 | | ||
| | \`checksums.txt\` | - | 文件完整性校验 | | ||
| ### 🛠️ 安装方式 | ||
| #### 一键安装(推荐) | ||
| \`\`\`bash | ||
| curl -fsSL https://get.runpanel.dev/install.sh | bash | ||
| \`\`\` | ||
| #### 手动安装 | ||
| 1. 下载对应平台的 tar.gz 文件 | ||
| 2. 解压: \`tar -xzf runpanel-embedded-linux-*.tar.gz\` | ||
| 3. 进入目录: \`cd runpanel-embedded-linux-*/\` | ||
| 4. 启动: \`./start.sh\` | ||
| ### 🌐 访问地址 | ||
| - 管理界面: http://localhost:8081 | ||
| - API文档: http://localhost:8081/docs | ||
| ### 📋 版本信息 | ||
| - 版本号: ${{ env.VERSION }} | ||
| - 构建时间: $(date -u +"%Y-%m-%d %H:%M:%S UTC") | ||
| - 前端版本: ${{ needs.check-frontend.outputs.frontend-version }} | ||
| - Git提交: $(git rev-parse --short HEAD) | ||
| ### 🔧 系统要求 | ||
| - 操作系统: Linux (Ubuntu 18.04+, CentOS 7+, Debian 9+) | ||
| - 架构: x86_64 或 ARM64 | ||
| - 内存: 最少 512MB,推荐 1GB+ | ||
| - 磁盘: 最少 100MB 可用空间 | ||
| ### 📞 技术支持 | ||
| 如有问题,请提交 [Issue](https://github.com/Run-Panel/RunPanel/issues) 或联系技术支持。 | ||
| EOF | ||
| # 输出到GitHub环境变量 | ||
| echo "RELEASE_NOTES<<EOF" >> $GITHUB_ENV | ||
| cat release-notes.md >> $GITHUB_ENV | ||
| echo "EOF" >> $GITHUB_ENV | ||
| - name: Create Release | ||
| if: | | ||
| github.event_name == 'release' || | ||
| startsWith(github.ref, 'refs/tags/') || | ||
| (github.event_name == 'workflow_dispatch' && github.event.inputs.dry_run != 'true') | ||
| uses: softprops/action-gh-release@v1 | ||
| with: | ||
| tag_name: ${{ env.VERSION }} | ||
| name: RunPanel ${{ env.VERSION }} | ||
| body: ${{ env.RELEASE_NOTES }} | ||
| files: release-files/* | ||
| draft: false | ||
| prerelease: false | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| - name: Upload to custom endpoint (optional) | ||
| if: false # 设置为 true 启用 | ||
| run: | | ||
| # scp release-files/* user@get.runpanel.dev:/var/www/releases/latest/ | ||
| # 通知构建结果 | ||
| notify: | ||
| needs: [release] | ||
| runs-on: ubuntu-latest | ||
| if: always() | ||
| steps: | ||
| - name: Notify success | ||
| if: needs.release.result == 'success' && !(github.event_name == 'workflow_dispatch' && github.event.inputs.dry_run == 'true') | ||
| run: | | ||
| echo "✅ RunPanel ${{ needs.release.outputs.version || 'latest' }} 发布成功!" | ||
| echo "📦 Release 页面: ${{ github.server_url }}/${{ github.repository }}/releases" | ||
| - name: Notify dry-run success | ||
| if: needs.release.result == 'success' && github.event_name == 'workflow_dispatch' && github.event.inputs.dry_run == 'true' | ||
| run: | | ||
| echo "🧪 Dry Run 成功:构建与制品产出完成(未创建Release)。" | ||
| echo "🔍 请在该工作流运行页面下载 artifacts 并检查。" | ||
| - name: Notify failure | ||
| if: needs.release.result == 'failure' | ||
| run: | | ||
| echo "❌ RunPanel 发布失败" | ||
| echo "请检查构建日志: ${{ github.server_url }}/${{ github.repository }}/actions" | ||