feat(domain-modeling): add domain events support and optimistic concu… #405
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: CI | |
| on: | |
| push: | |
| branches: [main] | |
| tags: ["v*"] | |
| pull_request: | |
| branches: [main] | |
| workflow_dispatch: | |
| env: | |
| DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true | |
| DOTNET_NOLOGO: true | |
| DOTNET_SDK_VERSION: "10.0.x" | |
| jobs: | |
| # Build job - runs first, creates build artifacts for test jobs | |
| build: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Setup .NET SDK | |
| uses: actions/setup-dotnet@v5 | |
| with: | |
| dotnet-version: ${{ env.DOTNET_SDK_VERSION }} | |
| - name: Cache NuGet packages | |
| uses: actions/cache@v5 | |
| with: | |
| path: ~/.nuget/packages | |
| key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj', '**/Directory.*.props') }} | |
| restore-keys: | | |
| ${{ runner.os }}-nuget- | |
| - name: Restore | |
| run: dotnet restore Encina.slnx | |
| - name: Build | |
| run: dotnet build Encina.slnx --configuration Release --no-restore | |
| - name: Upload build artifacts | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: build-output | |
| path: | | |
| **/bin/Release/** | |
| **/obj/**/*.assets.json | |
| retention-days: 1 | |
| # Unit tests - split into shards for parallel execution | |
| test-unit: | |
| needs: build | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| shard: | |
| - name: Testing | |
| filter: "FullyQualifiedName~Encina.UnitTests.Testing" | |
| - name: Messaging | |
| filter: "FullyQualifiedName~Encina.UnitTests.Messaging|FullyQualifiedName~Encina.UnitTests.Caching" | |
| - name: Data | |
| filter: "FullyQualifiedName~Encina.UnitTests.EntityFrameworkCore|FullyQualifiedName~Encina.UnitTests.Dapper|FullyQualifiedName~Encina.UnitTests.ADO|FullyQualifiedName~Encina.UnitTests.MongoDB|FullyQualifiedName~Encina.UnitTests.Marten" | |
| - name: Cloud | |
| filter: "FullyQualifiedName~Encina.UnitTests.AzureFunctions|FullyQualifiedName~Encina.UnitTests.AzureServiceBus|FullyQualifiedName~Encina.UnitTests.Polly|FullyQualifiedName~Encina.UnitTests.AwsLambda|FullyQualifiedName~Encina.UnitTests.Aspire|FullyQualifiedName~Encina.UnitTests.OpenTelemetry" | |
| - name: Remaining | |
| filter: "FullyQualifiedName~Encina.UnitTests.Core|FullyQualifiedName~Encina.UnitTests.DomainModeling|FullyQualifiedName~Encina.UnitTests.AspNetCore|FullyQualifiedName~Encina.UnitTests.gRPC|FullyQualifiedName~Encina.UnitTests.SignalR|FullyQualifiedName~Encina.UnitTests.GuardClauses|FullyQualifiedName~Encina.UnitTests.MQTT|FullyQualifiedName~Encina.UnitTests.NATS|FullyQualifiedName~Encina.UnitTests.RabbitMQ|FullyQualifiedName~Encina.UnitTests.AmazonSQS|FullyQualifiedName~Encina.UnitTests.Kafka|FullyQualifiedName~Encina.UnitTests.Workflows|FullyQualifiedName~Encina.UnitTests.MiniValidator|FullyQualifiedName~Encina.UnitTests.FluentValidation|FullyQualifiedName~Encina.UnitTests.DataAnnotations|FullyQualifiedName~Encina.UnitTests.Quartz|FullyQualifiedName~Encina.UnitTests.Hangfire|FullyQualifiedName~Encina.UnitTests.Extensions|FullyQualifiedName~Encina.UnitTests.Refit|FullyQualifiedName~Encina.UnitTests.Cli" | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/setup-dotnet@v5 | |
| with: | |
| dotnet-version: ${{ env.DOTNET_SDK_VERSION }} | |
| - uses: actions/download-artifact@v7 | |
| with: | |
| name: build-output | |
| - name: Run Unit tests (${{ matrix.shard.name }}) | |
| run: | | |
| dotnet test tests/Encina.UnitTests/Encina.UnitTests.csproj --no-build -c Release \ | |
| --filter "${{ matrix.shard.filter }}" \ | |
| --logger "console;verbosity=minimal" \ | |
| -- xunit.parallelizeTestCollections=true | |
| continue-on-error: true | |
| # Integration tests - split into shards for parallel execution and reduced disk usage | |
| test-integration: | |
| needs: build | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| shard: | |
| - name: ADO | |
| filter: "FullyQualifiedName~IntegrationTests.ADO" | |
| - name: Dapper | |
| filter: "FullyQualifiedName~IntegrationTests.Dapper" | |
| - name: EFCore | |
| filter: "FullyQualifiedName~IntegrationTests.Infrastructure" | |
| steps: | |
| - name: Free disk space | |
| run: | | |
| echo "=== Disk space before cleanup ===" | |
| df -h / | |
| sudo rm -rf /usr/share/dotnet/shared/Microsoft.AspNetCore.App/6.0.* || true | |
| sudo rm -rf /usr/share/dotnet/shared/Microsoft.AspNetCore.App/7.0.* || true | |
| sudo rm -rf /usr/share/dotnet/shared/Microsoft.AspNetCore.App/8.0.* || true | |
| sudo rm -rf /usr/share/dotnet/shared/Microsoft.NETCore.App/6.0.* || true | |
| sudo rm -rf /usr/share/dotnet/shared/Microsoft.NETCore.App/7.0.* || true | |
| sudo rm -rf /usr/share/dotnet/shared/Microsoft.NETCore.App/8.0.* || true | |
| sudo rm -rf /usr/local/lib/android || true | |
| sudo rm -rf /opt/ghc || true | |
| sudo rm -rf /opt/hostedtoolcache/CodeQL || true | |
| echo "=== Disk space after cleanup ===" | |
| df -h / | |
| - uses: actions/checkout@v6 | |
| - uses: actions/setup-dotnet@v5 | |
| with: | |
| dotnet-version: ${{ env.DOTNET_SDK_VERSION }} | |
| - uses: actions/download-artifact@v7 | |
| with: | |
| name: build-output | |
| - name: Run Integration tests (${{ matrix.shard.name }}) | |
| run: | | |
| dotnet test tests/Encina.IntegrationTests/Encina.IntegrationTests.csproj --no-build -c Release \ | |
| --filter "${{ matrix.shard.filter }}" \ | |
| --logger "console;verbosity=minimal" \ | |
| -- xunit.parallelizeTestCollections=true | |
| continue-on-error: true | |
| # Contract tests - consolidated project | |
| test-contract: | |
| needs: build | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/setup-dotnet@v5 | |
| with: | |
| dotnet-version: ${{ env.DOTNET_SDK_VERSION }} | |
| - uses: actions/download-artifact@v7 | |
| with: | |
| name: build-output | |
| - name: Run Contract tests | |
| run: | | |
| dotnet test tests/Encina.ContractTests/Encina.ContractTests.csproj --no-build -c Release \ | |
| --logger "console;verbosity=minimal" | |
| continue-on-error: true | |
| # Property tests - consolidated project | |
| test-property: | |
| needs: build | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/setup-dotnet@v5 | |
| with: | |
| dotnet-version: ${{ env.DOTNET_SDK_VERSION }} | |
| - uses: actions/download-artifact@v7 | |
| with: | |
| name: build-output | |
| - name: Run Property tests | |
| run: | | |
| dotnet test tests/Encina.PropertyTests/Encina.PropertyTests.csproj --no-build -c Release \ | |
| --logger "console;verbosity=minimal" | |
| continue-on-error: true | |
| # Guard tests - consolidated project | |
| test-guard: | |
| needs: build | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/setup-dotnet@v5 | |
| with: | |
| dotnet-version: ${{ env.DOTNET_SDK_VERSION }} | |
| - uses: actions/download-artifact@v7 | |
| with: | |
| name: build-output | |
| - name: Run Guard tests | |
| run: | | |
| dotnet test tests/Encina.GuardTests/Encina.GuardTests.csproj --no-build -c Release \ | |
| --logger "console;verbosity=minimal" | |
| continue-on-error: true | |
| # EF Core multi-provider integration tests | |
| # Tests EF Core against all 4 database providers (Sqlite, SqlServer, PostgreSQL, MySQL) | |
| # to ensure LINQ translation and provider-specific behavior works correctly across providers. | |
| # MySQL tests are skipped until Pomelo.EntityFrameworkCore.MySql v10 is released. | |
| # Note: Oracle was removed from pre-1.0 scope (see ADR-009) | |
| test-ef-providers: | |
| needs: build | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 25 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| database: | |
| - name: Sqlite | |
| # SQLite uses in-process database, no service container needed | |
| trait: "Sqlite" | |
| - name: SqlServer | |
| trait: "SqlServer" | |
| - name: PostgreSQL | |
| trait: "PostgreSQL" | |
| - name: MySQL | |
| trait: "MySQL" | |
| # Service containers for database providers (conditionally started based on matrix) | |
| services: | |
| sqlserver: | |
| image: ${{ matrix.database.name == 'SqlServer' && 'mcr.microsoft.com/mssql/server:2022-latest' || '' }} | |
| env: | |
| ACCEPT_EULA: Y | |
| MSSQL_SA_PASSWORD: Encina_Test_123! | |
| options: >- | |
| --health-cmd "/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P Encina_Test_123! -C -Q 'SELECT 1' || exit 1" | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 10 | |
| ports: | |
| - 1433:1433 | |
| postgres: | |
| image: ${{ matrix.database.name == 'PostgreSQL' && 'postgres:16' || '' }} | |
| env: | |
| POSTGRES_USER: encina | |
| POSTGRES_PASSWORD: encina_test | |
| POSTGRES_DB: encina_test | |
| options: >- | |
| --health-cmd pg_isready | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| ports: | |
| - 5432:5432 | |
| mysql: | |
| image: ${{ matrix.database.name == 'MySQL' && 'mysql:8' || '' }} | |
| env: | |
| MYSQL_ROOT_PASSWORD: encina_test | |
| MYSQL_DATABASE: encina_test | |
| options: >- | |
| --health-cmd "mysqladmin ping -h localhost" | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| ports: | |
| - 3306:3306 | |
| env: | |
| # Connection strings for each database provider | |
| ConnectionStrings__SqlServer: "Server=localhost,1433;Database=encina_test;User Id=sa;Password=Encina_Test_123!;TrustServerCertificate=true" | |
| ConnectionStrings__PostgreSQL: "Host=localhost;Port=5432;Database=encina_test;Username=encina;Password=encina_test" | |
| ConnectionStrings__MySQL: "Server=localhost;Port=3306;Database=encina_test;User=root;Password=encina_test" | |
| ConnectionStrings__Sqlite: "Data Source=encina_test.db" | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/setup-dotnet@v5 | |
| with: | |
| dotnet-version: ${{ env.DOTNET_SDK_VERSION }} | |
| - uses: actions/download-artifact@v7 | |
| with: | |
| name: build-output | |
| - name: Run EF Core ${{ matrix.database.name }} tests | |
| run: | | |
| # Filter for EF Core tests with specific database trait | |
| # Tests must have [Trait("Database", "{Provider}")] to be included | |
| dotnet test tests/Encina.IntegrationTests/Encina.IntegrationTests.csproj --no-build -c Release \ | |
| --filter "FullyQualifiedName~EntityFrameworkCore&Database=${{ matrix.database.trait }}" \ | |
| --logger "console;verbosity=minimal" \ | |
| -- xunit.parallelizeTestCollections=true | |
| continue-on-error: true | |
| - name: Upload test results | |
| if: always() | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: ef-test-results-${{ matrix.database.name }} | |
| path: artifacts/test-results | |
| if-no-files-found: ignore | |
| # Pack and publish - runs after all tests | |
| pack: | |
| needs: | |
| - test-unit | |
| - test-integration | |
| - test-contract | |
| - test-property | |
| - test-guard | |
| - test-ef-providers | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| if: always() && needs.build.result == 'success' | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/setup-dotnet@v5 | |
| with: | |
| dotnet-version: ${{ env.DOTNET_SDK_VERSION }} | |
| - name: Cache NuGet packages | |
| uses: actions/cache@v5 | |
| with: | |
| path: ~/.nuget/packages | |
| key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj', '**/Directory.*.props') }} | |
| restore-keys: | | |
| ${{ runner.os }}-nuget- | |
| - name: Pack | |
| run: dotnet pack src/Encina/Encina.csproj --configuration Release --output artifacts | |
| - name: Upload package artifacts | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: encina-nuget | |
| path: artifacts/*.nupkg | |
| - name: Publish to GitHub Packages | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| env: | |
| GITHUB_PACKAGES_SOURCE: https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json | |
| NUGET_API_KEY: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| dotnet nuget push artifacts/*.nupkg \ | |
| --source "$GITHUB_PACKAGES_SOURCE" \ | |
| --api-key "$NUGET_API_KEY" \ | |
| --skip-duplicate |