name: CI on: push: branches: [main, master] tags: ["v*"] pull_request: branches: [main, master] env: GO_VERSION: "1.22.2" jobs: quality-gates: name: Quality Gates 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: Install dependencies run: | sudo apt-get update sudo apt-get install -y bc chromium-browser - name: Download Go dependencies run: go mod download - name: Run quality gates run: bash ./scripts/test/verify_quality_gates.sh env: # CI environment may have socket restrictions ALLOW_BLOCKED_FRONTEND_SMOKE: "1" ALLOW_BLOCKED_INTEGRATION: "0" build: name: Build & Test runs-on: ubuntu-latest needs: quality-gates 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 with race detector 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 }} 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: | # Start container in background for health check docker run -d --name crm-test \ -e SUB2API_CRM_ADMIN_TOKEN=test-token \ -p 8080:8080 \ sub2api-cn-relay-manager:test # Wait for health endpoint for i in {1..30}; do if curl -s http://localhost:8080/healthz | grep -q "ok"; then echo "Health check passed" break fi if [ $i -eq 30 ]; then echo "Health check failed after 30 seconds" docker logs crm-test exit 1 fi sleep 1 done # Cleanup docker stop crm-test docker rm crm-test - name: Verify binary works run: | # Check binary exists and can show version info docker run --rm sub2api-cn-relay-manager:test --version || true release: name: Release runs-on: ubuntu-latest needs: [quality-gates, 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 }}