name: CI/CD Pipeline on: push: branches: [ main, develop ] pull_request: branches: [ main, develop ] release: types: [ published ] env: REGISTRY: docker.io IMAGE_NAME: btouchard/ackify-ce jobs: test: name: Run Tests runs-on: ubuntu-latest services: postgres: image: postgres:15-alpine env: POSTGRES_USER: postgres POSTGRES_PASSWORD: testpassword POSTGRES_DB: ackify_test options: >- --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 ports: - 5432:5432 steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Go uses: actions/setup-go@v4 with: go-version: '1.24.5' cache: true - name: Download dependencies run: go mod download - name: Run go fmt check run: | if [ "$(gofmt -s -l . | wc -l)" -gt 0 ]; then echo "The following files need to be formatted:" gofmt -s -l . exit 1 fi - name: Run go vet run: go vet ./... - name: Run unit tests env: APP_BASE_URL: "http://localhost:8080" APP_ORGANISATION: "Test Org" OAUTH_CLIENT_ID: "test-client-id" OAUTH_CLIENT_SECRET: "test-client-secret" OAUTH_COOKIE_SECRET: "dGVzdC1jb29raWUtc2VjcmV0LXRlc3QtY29va2llLXNlY3JldA==" run: go test -v -race -short ./... - name: Run integrations tests env: DB_DSN: "postgres://postgres:testpassword@localhost:5432/ackify_test?sslmode=disable" INTEGRATION_TESTS: "true" run: go test -v -race -tags=integrations ./internal/infrastructure/database/... - name: Generate coverage report env: DB_DSN: "postgres://postgres:testpassword@localhost:5432/ackify_test?sslmode=disable" INTEGRATION_TESTS: "true" APP_BASE_URL: "http://localhost:8080" APP_ORGANISATION: "Test Org" OAUTH_CLIENT_ID: "test-client-id" OAUTH_CLIENT_SECRET: "test-client-secret" OAUTH_COOKIE_SECRET: "dGVzdC1jb29raWUtc2VjcmV0LXRlc3QtY29va2llLXNlY3JldA==" run: go test -v -race -tags=integrations -coverprofile=coverage.out ./... - name: Upload coverage to Codecov if: success() uses: codecov/codecov-action@v3 with: file: ./coverage.out flags: unittests,integrations name: codecov-umbrella build: name: Build and Push Docker Image runs-on: ubuntu-latest needs: test if: github.event_name != 'pull_request' steps: - name: Checkout code uses: actions/checkout@v4 - name: Compute IMAGE_TAG run: | # Strip leading 'v' from tag refs; leave branches unchanged echo "IMAGE_TAG=${GITHUB_REF_NAME#v}" >> "$GITHUB_ENV" - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Log in to Docker Hub uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Extract metadata id: meta uses: docker/metadata-action@v5 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} tags: | type=ref,event=branch type=ref,event=pr type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} type=semver,pattern={{major}} type=sha,prefix={{branch}}-,enable={{is_default_branch}} type=sha,enable=false type=raw,value=latest,enable={{is_default_branch}} - name: Build and push Docker image uses: docker/build-push-action@v5 with: context: . file: ./Dockerfile platforms: linux/amd64,linux/arm64 push: true tags: | ${{ steps.meta.outputs.tags }} ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max build-args: | VERSION=${{ github.ref_name }} COMMIT=${{ github.sha }} BUILD_DATE=${{ github.event.head_commit.timestamp }} security: name: Security Scan runs-on: ubuntu-latest needs: build if: github.event_name != 'pull_request' steps: - name: Checkout code uses: actions/checkout@v4 - name: Compute IMAGE_TAG run: | # Strip leading 'v' from tag refs; leave branches unchanged echo "IMAGE_TAG=${GITHUB_REF_NAME#v}" >> "$GITHUB_ENV" - name: Run Trivy vulnerability scanner uses: aquasecurity/trivy-action@master with: image-ref: '${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }}' format: 'sarif' output: 'trivy-results.sarif' # - name: Upload Trivy scan results to GitHub Security tab # uses: github/codeql-action/upload-sarif@v2 # if: always() # with: # sarif_file: 'trivy-results.sarif' notify: name: Notify runs-on: ubuntu-latest needs: [test, build, security] if: always() && github.event_name != 'pull_request' steps: - name: Notify success if: needs.test.result == 'success' && needs.build.result == 'success' run: | echo "✅ CI/CD Pipeline completed successfully!" echo "🚀 Image pushed: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }}" - name: Notify failure if: needs.test.result == 'failure' || needs.build.result == 'failure' run: | echo "❌ CI/CD Pipeline failed!" echo "Please check the logs above for details." exit 1