chore(api): remove routes api versioning, refactor gateway proxy, upgrade to go 1.25.5 #89
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: service | |
| on: | |
| push: | |
| tags: | |
| - "v*" # Trigger on release tags | |
| pull_request: | |
| branches: | |
| - main | |
| jobs: | |
| detect-changes: | |
| runs-on: tenki-standard-autoscale | |
| outputs: | |
| typed_services: ${{ steps.determine.outputs.typed_services }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 # Need full history to find previous tags | |
| - name: Get previous release tag for comparison | |
| id: prev_tag | |
| if: startsWith(github.ref, 'refs/tags/') | |
| run: | | |
| # Get the previous tag for comparison (excluding the current tag) | |
| CURRENT_TAG="${{ github.ref_name }}" | |
| PREV_TAG=$(git tag --sort=-v:refname | grep -v "^${CURRENT_TAG}$" | head -n 1) | |
| if [ -z "$PREV_TAG" ]; then | |
| echo "No previous tag found, will compare against initial commit" | |
| PREV_TAG=$(git rev-list --max-parents=0 HEAD) | |
| fi | |
| echo "base=$PREV_TAG" >> $GITHUB_OUTPUT | |
| echo "Comparing against previous tag: $PREV_TAG" | |
| - name: Use path filter to detect changes | |
| id: filter | |
| uses: dorny/paths-filter@v3 | |
| with: | |
| base: ${{ steps.prev_tag.outputs.base || github.base_ref }} | |
| filters: | | |
| api-gateway: | |
| - 'api-gateway/**' | |
| - 'pkg/**' | |
| - 'proto/**' | |
| - 'go.mod' | |
| - 'go.sum' | |
| graphql-gateway: | |
| - 'graphql-gateway/**' | |
| - 'auth-service/graph/schema/**/*.graphql' | |
| - 'chat-service/graph/schema/**/*.graphql' | |
| auth-service: | |
| - 'auth-service/**' | |
| - 'pkg/**' | |
| - 'proto/**' | |
| - 'go.mod' | |
| - 'go.sum' | |
| product-service: | |
| - 'product-service/**' | |
| - 'pkg/**' | |
| - 'proto/**' | |
| - 'go.mod' | |
| - 'go.sum' | |
| order-service: | |
| - 'order-service/**' | |
| - 'pkg/**' | |
| - 'proto/**' | |
| - 'go.mod' | |
| - 'go.sum' | |
| payment-service: | |
| - 'payment-service/**' | |
| - 'pkg/**' | |
| - 'proto/**' | |
| - 'go.mod' | |
| - 'go.sum' | |
| fulfillment-service: | |
| - 'fulfillment-service/**' | |
| - 'pkg/**' | |
| - 'proto/**' | |
| - 'go.mod' | |
| - 'go.sum' | |
| notification-service: | |
| - 'notification-service/**' | |
| - 'pkg/**' | |
| - 'proto/**' | |
| - 'go.mod' | |
| - 'go.sum' | |
| search-service: | |
| - 'search-service/**' | |
| - 'pkg/**' | |
| - 'proto/**' | |
| - 'go.mod' | |
| - 'go.sum' | |
| chat-service: | |
| - 'chat-service/**' | |
| - 'pkg/**' | |
| - 'proto/**' | |
| - 'go.mod' | |
| - 'go.sum' | |
| cart-service: | |
| - 'cart-service/**' | |
| - 'pkg/**' | |
| - 'proto/**' | |
| - 'go.mod' | |
| - 'go.sum' | |
| - name: Determine and classify services | |
| id: determine | |
| run: | | |
| # Always use path filter results for service detection | |
| # This enables independent service versioning - only changed services are built | |
| echo "Using path filter to detect changed services" | |
| typed_services=$(echo '${{ steps.filter.outputs.changes }}' | jq -c 'map({ | |
| name: ., | |
| type: (if . == "graphql-gateway" then "node" else "go" end) | |
| })') | |
| if [[ "${{ github.ref }}" == refs/tags/* ]]; then | |
| echo "Building changed services for release tag ${{ github.ref_name }}" | |
| else | |
| echo "Building changed services for PR/branch" | |
| fi | |
| echo "typed_services=$typed_services" >> $GITHUB_OUTPUT | |
| build-and-push: | |
| needs: detect-changes | |
| if: ${{ needs.detect-changes.outputs.typed_services != '[]' }} | |
| runs-on: tenki-standard-autoscale | |
| timeout-minutes: 30 | |
| strategy: | |
| fail-fast: true | |
| matrix: | |
| include: ${{ fromJson(needs.detect-changes.outputs.typed_services) }} | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| # Node.js setup | |
| - name: Setup node.js | |
| if: matrix.type == 'node' | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "20" | |
| - name: Setup pnpm | |
| if: matrix.type == 'node' | |
| uses: pnpm/action-setup@v4 | |
| with: | |
| version: 9 | |
| - name: Cache pnpm modules | |
| if: matrix.type == 'node' | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.pnpm-store | |
| key: ${{ runner.os }}-pnpm-${{ hashFiles(format('{0}/pnpm-lock.yaml', matrix.name)) }} | |
| restore-keys: | | |
| ${{ runner.os }}-pnpm- | |
| - name: Install node.js dependencies | |
| if: matrix.type == 'node' | |
| run: cd ${{ matrix.name }} && pnpm install | |
| # Go setup | |
| - name: Setup Go | |
| if: matrix.type == 'go' | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: 1.25.5 | |
| - name: Cache Go modules | |
| if: matrix.type == 'go' | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.cache/go-build | |
| ~/go/pkg/mod | |
| key: ${{ runner.os }}-go-${{ matrix.name }}-${{ hashFiles(format('{0}/go.sum', matrix.name), 'pkg/go.sum', 'proto/go.sum') }} | |
| restore-keys: | | |
| ${{ runner.os }}-go-${{ matrix.name }}- | |
| ${{ runner.os }}-go- | |
| - name: Install Go Tools | |
| if: matrix.type == 'go' | |
| run: | | |
| go install mvdan.cc/gofumpt@latest | |
| go install golang.org/x/tools/cmd/goimports@latest | |
| curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/HEAD/install.sh | sh -s -- -b $(go env GOPATH)/bin v2.4.0 | |
| go install golang.org/x/tools/cmd/deadcode@latest | |
| go install golang.org/x/vuln/cmd/govulncheck@latest | |
| - name: Check deadcode for ${{ matrix.name }} | |
| if: matrix.type == 'go' | |
| run: bash scripts/deadcode.sh ${{ matrix.name }} | |
| # Run lint/format/test scripts (scripts should auto-handle Node vs Go) | |
| - name: Run linter for ${{ matrix.name }} | |
| run: bash scripts/lint.sh ${{ matrix.name }} | |
| - name: Run format check for ${{ matrix.name }} | |
| run: bash scripts/format.sh ${{ matrix.name }} | |
| - name: Run security vulnerability Scan for ${{ matrix.name }} | |
| if: matrix.type == 'go' | |
| run: bash scripts/security.sh ${{ matrix.name }} | |
| - name: Run tests for ${{ matrix.name }} | |
| if: matrix.type == 'go' | |
| run: bash scripts/test.sh ${{ matrix.name }} | |
| - name: Upload test coverage to Codecov | |
| if: matrix.type == 'go' | |
| uses: codecov/codecov-action@v4 | |
| with: | |
| file: ./${{ matrix.name }}/coverage.out | |
| flags: ${{ matrix.name }} | |
| name: ${{ matrix.name }}-coverage | |
| fail_ci_if_error: false | |
| - name: Upload coverage reports | |
| if: always() && matrix.type == 'go' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ matrix.name }}-coverage | |
| path: | | |
| ./${{ matrix.name }}/coverage.out | |
| ./${{ matrix.name }}/coverage.html | |
| # Docker build & push | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| with: | |
| driver-opts: | | |
| image=moby/buildkit:latest | |
| buildkitd-config-inline: | | |
| [registry."docker.io"] | |
| mirrors = [] | |
| - name: Login to Docker Hub | |
| uses: docker/login-action@v3 | |
| with: | |
| username: ${{ secrets.DOCKERHUB_USERNAME }} | |
| password: ${{ secrets.DOCKERHUB_TOKEN }} | |
| - name: Login to GitHub Container Registry | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Extract metadata for Docker | |
| id: meta | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ghcr.io/${{ github.repository_owner }}/go-micro-commerce/${{ matrix.name }} | |
| tags: | | |
| type=semver,pattern={{version}} | |
| type=semver,pattern={{major}}.{{minor}} | |
| type=raw,value=latest | |
| - name: Build and push Docker image | |
| uses: docker/build-push-action@v6 | |
| id: build | |
| with: | |
| context: . # Use root as context to access pkg directory | |
| file: ./${{ matrix.name }}/Dockerfile | |
| push: ${{ github.event_name != 'pull_request' }} | |
| tags: ${{ steps.meta.outputs.tags }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| load: true # Load image locally for security scanning | |
| cache-from: type=registry,ref=ghcr.io/${{ github.repository_owner }}/go-micro-commerce/${{ matrix.name }}:buildcache | |
| cache-to: type=registry,ref=ghcr.io/${{ github.repository_owner }}/go-micro-commerce/${{ matrix.name }}:buildcache,mode=max | |
| # Build and push migration images for Go services | |
| - name: Check if migration Dockerfile exists | |
| if: matrix.type == 'go' | |
| id: check_migrations | |
| run: | | |
| if [ -f "${{ matrix.name }}/Dockerfile.migrations" ]; then | |
| echo "exists=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "exists=false" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Extract metadata for Migration Docker image | |
| if: matrix.type == 'go' && steps.check_migrations.outputs.exists == 'true' | |
| id: meta_migrations | |
| uses: docker/metadata-action@v5 | |
| with: | |
| images: ghcr.io/${{ github.repository_owner }}/go-micro-commerce/${{ matrix.name }}-migrations | |
| tags: | | |
| type=sha,prefix= | |
| type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }} | |
| type=semver,pattern={{version}} | |
| type=semver,pattern={{major}}.{{minor}} | |
| - name: Build and push Migration Docker image | |
| if: matrix.type == 'go' && steps.check_migrations.outputs.exists == 'true' | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: ./${{ matrix.name }} | |
| file: ./${{ matrix.name }}/Dockerfile.migrations | |
| push: ${{ github.event_name != 'pull_request' }} | |
| tags: ${{ steps.meta_migrations.outputs.tags }} | |
| labels: ${{ steps.meta_migrations.outputs.labels }} | |
| cache-from: type=registry,ref=ghcr.io/${{ github.repository_owner }}/go-micro-commerce/${{ matrix.name }}-migrations:buildcache | |
| cache-to: type=registry,ref=ghcr.io/${{ github.repository_owner }}/go-micro-commerce/${{ matrix.name }}-migrations:buildcache,mode=max | |
| # - name: Run Trivy vulnerability scanner | |
| # uses: aquasecurity/trivy-action@master | |
| # with: | |
| # image-ref: ${{ steps.meta.outputs.tags }} | |
| # format: "sarif" | |
| # output: "trivy-results.sarif" | |
| # - name: Upload Trivy scan results to GitHub Security tab | |
| # uses: github/codeql-action/upload-sarif@v3 | |
| # if: always() | |
| # with: | |
| # sarif_file: "trivy-results.sarif" | |
| # Note: Kustomization updates are handled by the 'update-kustomize.yml' workflow | |
| # which detects changed services using the same path filter and updates only those | |
| # kustomization files. This enables independent service versioning. | |
| - name: Generate job summary | |
| if: always() | |
| run: | | |
| echo "## Build Summary for ${{ matrix.name }}" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Service**: ${{ matrix.name }}" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Type**: ${{ matrix.type }}" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Status**: ${{ job.status }}" >> $GITHUB_STEP_SUMMARY | |
| echo "- **Commit**: ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY | |
| if [ "${{ matrix.type }}" = "go" ] && [ -f "${{ matrix.name }}/coverage.out" ]; then | |
| COVERAGE=$(go tool cover -func=${{ matrix.name }}/coverage.out | grep total: | awk '{print $3}') | |
| echo "- **Test Coverage**: $COVERAGE" >> $GITHUB_STEP_SUMMARY | |
| fi | |
| if [ "${{ steps.check_migrations.outputs.exists }}" = "true" ]; then | |
| echo "- **Migration Image**: Built and pushed" >> $GITHUB_STEP_SUMMARY | |
| fi |