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 }}