From 6865b3a33b4feb05797c1ef653fa0b4d1ed0e7c8 Mon Sep 17 00:00:00 2001 From: phamnazage-jpg Date: Tue, 2 Jun 2026 06:47:06 +0800 Subject: [PATCH] =?UTF-8?q?ci:=20B-04=20=E6=B7=BB=E5=8A=A0=20GitHub=20Acti?= =?UTF-8?q?ons=20CI/CD=20=E5=B7=A5=E4=BD=9C=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加完整的 CI 流水线:构建、测试、覆盖率检查 - 集成 golangci-lint 静态代码分析 - 集成 gosec 和 govulncheck 安全扫描 - 添加 Docker 镜像构建验证 - 添加 Release 自动打包(多架构支持) - 设置覆盖率阈值 60% --- .github/workflows/ci.yml | 165 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..e7847cc8 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,165 @@ +name: CI + +on: + push: + branches: [main, master] + tags: ['v*'] + pull_request: + branches: [main, master] + +env: + GO_VERSION: '1.22.2' + +jobs: + build: + name: Build & Test + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: ${{ env.GO_VERSION }} + cache: true + + - name: Download dependencies + run: go mod download + + - name: Build binaries + run: | + go build -v ./cmd/server + go build -v ./cmd/cli + + - name: Run unit tests + run: go test -v -race -count=1 ./internal/... + + - name: Generate coverage report + run: go test -race -coverprofile=coverage.out -covermode=atomic ./internal/... + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v4 + with: + files: ./coverage.out + fail_ci_if_error: false + verbose: true + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + + - name: Check coverage threshold + run: | + COVERAGE=$(go tool cover -func=coverage.out | grep total | awk '{print $3}' | sed 's/%//') + echo "Total coverage: $COVERAGE%" + if (( $(echo "$COVERAGE < 60" | bc -l) )); then + echo "Coverage $COVERAGE% is below threshold 60%" + exit 1 + fi + + lint: + name: Lint + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: ${{ env.GO_VERSION }} + cache: true + + - name: Run golangci-lint + uses: golangci/golangci-lint-action@v6 + with: + version: latest + args: --timeout=5m + skip-cache: false + + security: + name: Security Scan + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: ${{ env.GO_VERSION }} + cache: true + + - name: Run gosec security scanner + uses: securego/gosec@master + with: + args: '-no-fail -fmt sarif -out results.sarif ./...' + + - name: Run govulncheck + uses: golang/govulncheck-action@v1 + with: + go-version-input: ${{ env.GO_VERSION }} + + - name: Upload SARIF results + uses: github/codeql-action/upload-sarif@v3 + if: always() + with: + sarif_file: results.sarif + + docker: + name: Docker Build + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build Docker image + uses: docker/build-push-action@v5 + with: + context: . + push: false + load: true + tags: sub2api-cn-relay-manager:test + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Test Docker image + run: | + docker run --rm sub2api-cn-relay-manager:test /app/server --version || true + docker run --rm sub2api-cn-relay-manager:test /app/cli --help || true + + release: + name: Release + runs-on: ubuntu-latest + needs: [build, lint, security, docker] + if: startsWith(github.ref, 'refs/tags/v') + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: ${{ env.GO_VERSION }} + cache: true + + - name: Build release binaries + run: | + mkdir -p dist + # Linux AMD64 + GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -X main.version=${{ github.ref_name }}" -o dist/server-linux-amd64 ./cmd/server + GOOS=linux GOARCH=amd64 go build -ldflags "-s -w -X main.version=${{ github.ref_name }}" -o dist/cli-linux-amd64 ./cmd/cli + # Linux ARM64 + GOOS=linux GOARCH=arm64 go build -ldflags "-s -w -X main.version=${{ github.ref_name }}" -o dist/server-linux-arm64 ./cmd/server + GOOS=linux GOARCH=arm64 go build -ldflags "-s -w -X main.version=${{ github.ref_name }}" -o dist/cli-linux-arm64 ./cmd/cli + ls -la dist/ + + - name: Create Release + uses: softprops/action-gh-release@v1 + with: + files: dist/* + generate_release_notes: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}