# Copyright (c) Abstract Machines # SPDX-License-Identifier: Apache-2.0 name: CI Pipeline on: push: branches: - main paths-ignore: - '**.md' - 'docs/**' - 'LICENSE' - 'MAINTAINERS' - 'CODEOWNERS' pull_request: branches: - main concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: check-certs: name: Check Certs runs-on: ubuntu-latest steps: - name: Checkout Code uses: actions/checkout@v6 - name: Fetch Certs run: | make fetch_certs if [[ -n $(git status --porcelain docker/addons/certs) ]]; then echo "Certs docker file is not up to date. Please update it" git diff docker/addons/certs exit 1 else exit 0 fi lint-proto: name: Lint Proto runs-on: ubuntu-latest steps: - name: Checkout Code uses: actions/checkout@v6 - name: Get Go version from go.mod id: go-version run: echo "version=$(grep '^go ' go.mod | awk '{print $2}')" >> $GITHUB_OUTPUT - name: Setup Go uses: actions/setup-go@v6 with: go-version: ${{ steps.go-version.outputs.version }} cache-dependency-path: "go.sum" - name: Install protolint run: | go install github.com/yoheimuta/protolint/cmd/protolint@latest - name: Lint Protobuf Files run: | protolint . lint-and-build: needs: [check-certs, lint-proto] uses: ./.github/workflows/lint-and-build.yaml detect-changes: name: Detect Changes runs-on: ubuntu-latest outputs: modules: ${{ steps.set-matrix.outputs.modules }} workflow_changed: ${{ steps.changes.outputs.workflow }} steps: - name: Checkout uses: actions/checkout@v6 with: fetch-depth: 0 - name: Check for changes in specific paths uses: dorny/paths-filter@v3 id: changes with: filters: | workflow: - ".github/workflows/tests.yaml" auth: - "auth/**" - "cmd/auth/**" - "auth.proto" - "auth.pb.go" - "auth_grpc.pb.go" - "pkg/ulid/**" - "pkg/uuid/**" channels: - "channels/**" - "cmd/channels/**" - "auth.pb.go" - "auth_grpc.pb.go" - "auth/**" - "pkg/sdk/**" - "clients/api/grpc/**" - "groups/api/grpc/**" - "domains/api/grpc/**" - "internal/grpc/**" cli: - "cli/**" - "cmd/cli/**" - "pkg/sdk/**" clients: - "clients/**" - "cmd/clients/**" - "auth.pb.go" - "auth_grpc.pb.go" - "auth/**" - "pkg/ulid/**" - "pkg/uuid/**" - "pkg/events/**" - "groups/api/grpc/**" - "channels/api/grpc/**" - "domains/api/grpc/**" - "internal/grpc/**" coap: - "coap/**" - "cmd/coap/**" - "auth.pb.go" - "auth_grpc.pb.go" - "clients/**" - "pkg/messaging/**" domains: - "domains/**" - "cmd/domains/**" - "auth.pb.go" - "auth_grpc.pb.go" - "auth/**" - "internal/grpc/**" groups: - "groups/**" - "cmd/groups/**" - "auth.pb.go" - "auth_grpc.pb.go" - "auth/**" - "pkg/ulid/**" - "pkg/uuid/**" - "clients/api/grpc/**" - "channels/api/grpc/**" - "domains/api/grpc/**" - "internal/grpc/**" http: - "http/**" - "cmd/http/**" - "auth.pb.go" - "auth_grpc.pb.go" - "clients/**" - "pkg/messaging/**" - "logger/**" internal: - "internal/**" journal: - "journal/**" - "cmd/journal/**" - "auth.pb.go" - "auth_grpc.pb.go" - "auth/**" - "pkg/events/**" logger: - "logger/**" mqtt: - "mqtt/**" - "cmd/mqtt/**" - "auth.pb.go" - "auth_grpc.pb.go" - "clients/**" - "pkg/messaging/**" - "logger/**" - "pkg/events/**" pkg-errors: - "pkg/errors/**" pkg-events: - "pkg/events/**" - "pkg/messaging/**" pkg-grpcclient: - "pkg/grpcclient/**" pkg-messaging: - "pkg/messaging/**" pkg-sdk: - "pkg/sdk/**" - "pkg/errors/**" - "pkg/groups/**" - "auth/**" - "http/**" - "internal/*" - "clients/**" - "users/**" - "channels/**" - "domains/**" - "groups/**" - "journal/**" - "api/http/**" pkg-transformers: - "pkg/transformers/**" pkg-ulid: - "pkg/ulid/**" pkg-uuid: - "pkg/uuid/**" users: - "users/**" - "cmd/users/**" - "auth.pb.go" - "auth_grpc.pb.go" - "auth/**" - "pkg/ulid/**" - "pkg/uuid/**" - "pkg/events/**" notifications: - "notifications/**" - "cmd/notifications/**" - "auth.pb.go" - "auth_grpc.pb.go" - "consumers/notifier.go" - "pkg/events/**" api: - "api/**" consumers: - "consumers/**" readers: - "readers/**" - name: Set matrix for changed modules id: set-matrix run: | modules=() if [[ "${{ steps.changes.outputs.workflow }}" == "true" || "${{ steps.changes.outputs.pkg-errors }}" == "true" ]]; then # If workflow or pkg/errors changed, test everything modules=("auth" "channels" "cli" "clients" "coap" "domains" "groups" "http" "internal" "journal" "logger" "mqtt" "pkg-errors" "pkg-events" "pkg-grpcclient" "pkg-messaging" "pkg-sdk" "pkg-transformers" "pkg-ulid" "pkg-uuid" "users" "notifications" "api" "consumers" "readers") else # Add only changed modules [[ "${{ steps.changes.outputs.auth }}" == "true" ]] && modules+=("auth") [[ "${{ steps.changes.outputs.channels }}" == "true" ]] && modules+=("channels") [[ "${{ steps.changes.outputs.cli }}" == "true" ]] && modules+=("cli") [[ "${{ steps.changes.outputs.clients }}" == "true" ]] && modules+=("clients") [[ "${{ steps.changes.outputs.coap }}" == "true" ]] && modules+=("coap") [[ "${{ steps.changes.outputs.domains }}" == "true" ]] && modules+=("domains") [[ "${{ steps.changes.outputs.groups }}" == "true" ]] && modules+=("groups") [[ "${{ steps.changes.outputs.http }}" == "true" ]] && modules+=("http") [[ "${{ steps.changes.outputs.internal }}" == "true" ]] && modules+=("internal") [[ "${{ steps.changes.outputs.journal }}" == "true" ]] && modules+=("journal") [[ "${{ steps.changes.outputs.logger }}" == "true" ]] && modules+=("logger") [[ "${{ steps.changes.outputs.mqtt }}" == "true" ]] && modules+=("mqtt") [[ "${{ steps.changes.outputs.pkg-errors }}" == "true" ]] && modules+=("pkg-errors") [[ "${{ steps.changes.outputs.pkg-events }}" == "true" ]] && modules+=("pkg-events") [[ "${{ steps.changes.outputs.pkg-grpcclient }}" == "true" ]] && modules+=("pkg-grpcclient") [[ "${{ steps.changes.outputs.pkg-messaging }}" == "true" ]] && modules+=("pkg-messaging") [[ "${{ steps.changes.outputs.pkg-sdk }}" == "true" ]] && modules+=("pkg-sdk") [[ "${{ steps.changes.outputs.pkg-transformers }}" == "true" ]] && modules+=("pkg-transformers") [[ "${{ steps.changes.outputs.pkg-ulid }}" == "true" ]] && modules+=("pkg-ulid") [[ "${{ steps.changes.outputs.pkg-uuid }}" == "true" ]] && modules+=("pkg-uuid") [[ "${{ steps.changes.outputs.users }}" == "true" ]] && modules+=("users") [[ "${{ steps.changes.outputs.notifications }}" == "true" ]] && modules+=("notifications") [[ "${{ steps.changes.outputs.api }}" == "true" ]] && modules+=("api") [[ "${{ steps.changes.outputs.consumers }}" == "true" ]] && modules+=("consumers") [[ "${{ steps.changes.outputs.readers }}" == "true" ]] && modules+=("readers") fi # Convert to JSON array json_modules=$(printf '%s\n' "${modules[@]}" | jq -R . | jq -s -c .) echo "modules=$json_modules" >> $GITHUB_OUTPUT echo "Testing modules: $json_modules" run-tests: name: Test ${{ matrix.module }} runs-on: ubuntu-latest needs: [lint-and-build, detect-changes] if: needs.detect-changes.outputs.modules != '[]' strategy: fail-fast: true max-parallel: 20 matrix: module: ${{ fromJSON(needs.detect-changes.outputs.modules) }} steps: - name: Checkout uses: actions/checkout@v6 - name: Get Go version from go.mod id: go-version run: echo "version=$(grep '^go ' go.mod | awk '{print $2}')" >> $GITHUB_OUTPUT - name: Setup Go uses: actions/setup-go@v6 with: go-version: ${{ steps.go-version.outputs.version }} cache-dependency-path: "go.sum" - name: Verify dependencies run: | go mod download go mod verify - name: Run ${{ matrix.module }} tests run: | # Map module names to directories case "${{ matrix.module }}" in pkg-errors) dir="pkg/errors" ;; pkg-events) dir="pkg/events" ;; pkg-grpcclient) dir="pkg/grpcclient" ;; pkg-messaging) dir="pkg/messaging" ;; pkg-sdk) dir="pkg/sdk" ;; pkg-transformers) dir="pkg/transformers" ;; pkg-ulid) dir="pkg/ulid" ;; pkg-uuid) dir="pkg/uuid" ;; *) dir="${{ matrix.module }}" ;; esac go test -mod=readonly --race -v -count=1 -failfast -coverprofile=coverage-${{ matrix.module }}.out ./$dir/... - name: Upload coverage uses: actions/upload-artifact@v7 with: name: coverage-${{ matrix.module }} path: coverage-${{ matrix.module }}.out retention-days: 1 upload-coverage: name: Upload Coverage runs-on: ubuntu-latest needs: run-tests if: always() && needs.run-tests.result != 'cancelled' steps: - name: Checkout uses: actions/checkout@v6 - name: Download all coverage artifacts uses: actions/download-artifact@v8 with: pattern: coverage-* path: coverage merge-multiple: true - name: Upload coverage to Codecov uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV }} directory: ./coverage files: ./coverage/*.out fail_ci_if_error: false verbose: true