diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..498a8fb --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,176 @@ +name: CI Pipeline + +on: + push: + branches: [ main, develop ] + pull_request: + branches: [ main, develop ] + +env: + GO_VERSION: '1.23.x' + +jobs: + # Lint and Format Check + lint: + name: Lint and Format + 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 }} + + - name: Install golangci-lint + run: | + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.55.2 + + - name: Run golangci-lint + run: golangci-lint run --timeout=5m + + - name: Check Go formatting + run: | + if [ "$(gofmt -s -l . | wc -l)" -gt 0 ]; then + echo "The following files are not properly formatted:" + gofmt -s -l . + exit 1 + fi + + # Build check + build: + name: Build Check + 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 }} + + - name: Cache Go modules + uses: actions/cache@v4 + with: + path: | + ~/.cache/go-build + ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + + - name: Download dependencies + run: go mod download + + - name: Build application + run: | + go build -v ./cmd/... + + - name: Check for vulnerabilities + run: | + go install golang.org/x/vuln/cmd/govulncheck@latest + govulncheck ./... + + # Unit Tests + unit-tests: + name: Unit Tests + runs-on: ubuntu-latest + needs: [lint, build] + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: ${{ env.GO_VERSION }} + + - name: Cache Go modules + uses: actions/cache@v4 + with: + path: | + ~/.cache/go-build + ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + + - name: Download dependencies + run: go mod download + + - name: Run unit tests + run: | + go test -v -race -coverprofile=coverage.out -covermode=atomic ./internal/... + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v4 + with: + file: ./coverage.out + flags: unittests + name: codecov-unit + fail_ci_if_error: false + + # Integration Tests + integration-tests: + name: Integration Tests + runs-on: ubuntu-latest + needs: [lint, build] + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: ${{ env.GO_VERSION }} + + - name: Cache Go modules + uses: actions/cache@v4 + with: + path: | + ~/.cache/go-build + ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + + - name: Download dependencies + run: go mod download + + - name: Run integration tests + run: | + chmod +x ./integrationtests/run_tests.sh + ./integrationtests/run_tests.sh + + - name: Run integration tests with coverage + run: | + go test -v -race -coverprofile=integration-coverage.out -covermode=atomic ./integrationtests/... + + - name: Upload integration coverage to Codecov + uses: codecov/codecov-action@v4 + with: + file: ./integration-coverage.out + flags: integrationtests + name: codecov-integration + fail_ci_if_error: false + + # Overall status check + test-summary: + name: Test Summary + runs-on: ubuntu-latest + needs: [unit-tests, integration-tests] + if: always() + steps: + - name: Check test results + run: | + if [[ "${{ needs.unit-tests.result }}" == "success" && "${{ needs.integration-tests.result }}" == "success" ]]; then + echo "✅ All tests passed!" + exit 0 + else + echo "❌ Some tests failed:" + echo " Unit tests: ${{ needs.unit-tests.result }}" + echo " Integration tests: ${{ needs.integration-tests.result }}" + exit 1 + fi diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml new file mode 100644 index 0000000..3b013dc --- /dev/null +++ b/.github/workflows/integration-tests.yml @@ -0,0 +1,74 @@ +name: Integration Tests + +on: + push: + branches: [ main, develop ] + pull_request: + branches: [ main, develop ] + +jobs: + integration-tests: + name: Run Integration Tests + runs-on: ubuntu-latest + + strategy: + matrix: + go-version: ['1.23.x'] + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: ${{ matrix.go-version }} + + - name: Cache Go modules + uses: actions/cache@v4 + with: + path: | + ~/.cache/go-build + ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + + - name: Download dependencies + run: go mod download + + - name: Verify dependencies + run: go mod verify + + - name: Set up test environment + run: | + # Create any necessary directories for test data + mkdir -p /tmp/test-data + + - name: Run integration tests + run: | + # Run integration tests using the existing script + chmod +x ./integrationtests/run_tests.sh + ./integrationtests/run_tests.sh + + - name: Run integration tests with coverage + run: | + # Also run integration tests with Go test for coverage + go test -v -race -coverprofile=integration-coverage.out -covermode=atomic ./integrationtests/... + + - name: Generate integration test coverage report + run: go tool cover -html=integration-coverage.out -o integration-coverage.html + + - name: Upload integration coverage to Codecov + uses: codecov/codecov-action@v4 + with: + file: ./integration-coverage.out + flags: integrationtests + name: codecov-integration + fail_ci_if_error: false + + - name: Upload integration coverage artifact + uses: actions/upload-artifact@v4 + with: + name: integration-coverage-report + path: integration-coverage.html diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml new file mode 100644 index 0000000..18d0f5c --- /dev/null +++ b/.github/workflows/unit-tests.yml @@ -0,0 +1,63 @@ +name: Unit Tests + +on: + push: + branches: [ main, develop ] + pull_request: + branches: [ main, develop ] + +jobs: + unit-tests: + name: Run Unit Tests + runs-on: ubuntu-latest + + strategy: + matrix: + go-version: ['1.23.x'] + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: ${{ matrix.go-version }} + + - name: Cache Go modules + uses: actions/cache@v4 + with: + path: | + ~/.cache/go-build + ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + + - name: Download dependencies + run: go mod download + + - name: Verify dependencies + run: go mod verify + + - name: Run unit tests + run: | + # Run unit tests with coverage, excluding integration tests + go test -v -race -coverprofile=coverage.out -covermode=atomic ./internal/... + + - name: Generate coverage report + run: go tool cover -html=coverage.out -o coverage.html + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v4 + with: + file: ./coverage.out + flags: unittests + name: codecov-umbrella + fail_ci_if_error: false + + - name: Upload coverage artifact + uses: actions/upload-artifact@v4 + with: + name: coverage-report + path: coverage.html diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..951409b --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,122 @@ +# GolangCI-Lint configuration +# See: https://golangci-lint.run/usage/configuration/ + +run: + timeout: 5m + modules-download-mode: readonly + +linters: + enable: + - errcheck + - gosimple + - govet + - ineffassign + - staticcheck + - typecheck + - unused + - asasalint + - asciicheck + - bidichk + - bodyclose + - containedctx + - contextcheck + - cyclop + - dupl + - durationcheck + - errname + - errorlint + - execinquery + - exhaustive + - exportloopref + - forbidigo + - funlen + - gci + - gocognit + - goconst + - gocritic + - gocyclo + - godox + - gofmt + - goimports + - gomnd + - gomoddirectives + - gomodguard + - goprintffuncname + - gosec + - grouper + - importas + - ireturn + - lll + - makezero + - misspell + - nakedret + - nestif + - nilerr + - nilnil + - noctx + - nolintlint + - nosnakecase + - nosprintfhostport + - predeclared + - promlinter + - reassign + - revive + - rowserrcheck + - sqlclosecheck + - stylecheck + - tenv + - testpackage + - thelper + - tparallel + - unconvert + - unparam + - usestdlibvars + - wastedassign + - whitespace + +linters-settings: + cyclop: + max-complexity: 15 + funlen: + lines: 100 + statements: 50 + gocognit: + min-complexity: 15 + gocyclo: + min-complexity: 15 + goconst: + min-len: 3 + min-occurrences: 3 + gomnd: + checks: + - argument + - case + - condition + - operation + - return + lll: + line-length: 120 + misspell: + locale: US + nestif: + min-complexity: 8 + +issues: + exclude-rules: + # Exclude some linters from running on tests files. + - path: _test\.go + linters: + - gomnd + - funlen + - gocyclo + - errcheck + - dupl + - gosec + # Ignore long lines in generated code + - path: docs/ + linters: + - lll + # Ignore magic numbers in test files + - path: integrationtests/ + linters: + - gomnd