diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 7475e9f..aa8ca62 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -1,134 +1,26 @@ -# Workleap.Extensions.MediatR - -Workleap.Extensions.MediatR is a .NET library that provides MediatR extensions, behaviors, and Roslyn analyzers for CQRS conventions. The library targets netstandard2.0 and net8.0 with additional ApplicationInsights integration. - -Always reference these instructions first and fallback to search or bash commands only when you encounter unexpected information that does not match the info here. - -## Working Effectively - -- **Install Required .NET SDK**: Download and install .NET 9.0.304 exactly as specified in global.json: - - `wget https://dot.net/v1/dotnet-install.sh -O /tmp/dotnet-install.sh && chmod +x /tmp/dotnet-install.sh` - - `/tmp/dotnet-install.sh --version 9.0.304 --install-dir ~/.dotnet` - - `export PATH="$HOME/.dotnet:$PATH"` -- **Install .NET 8.0 Runtime** (required for running tests): - - `/tmp/dotnet-install.sh --version 8.0.8 --runtime dotnet --install-dir ~/.dotnet` -- **Build the project**: - - Navigate to `src/` directory: `cd src` - - First restore: `dotnet restore` -- takes 50 seconds initially, 2 seconds subsequently. NEVER CANCEL. Set timeout to 30+ minutes. - - Debug build: `dotnet build -c Debug` -- takes 9 seconds after restore. NEVER CANCEL. Set timeout to 30+ minutes. - - Release build may fail with GitVersion issues in non-CI environments. Use Debug build for development. -- **Run tests**: - - `dotnet test -c Debug --no-build --verbosity normal` -- takes ~8 seconds if already built, ~17 seconds if a build is required. NEVER CANCEL. Set timeout to 30+ minutes. - - All 86 tests should pass when environment is properly configured. -- **Alternative: Use PowerShell build script** (may fail with GitVersion in non-CI): - - `pwsh ./Build.ps1` -- runs clean, build, test, pack sequence - -## Validation - -- **ALWAYS run through complete build and test cycle** after making changes to validate functionality. -- **ALWAYS run both main library tests and analyzer tests** to ensure Roslyn analyzers work correctly. -- **ALWAYS test MediatR extension functionality** by checking that the library properly registers with dependency injection. -- **NEVER make changes to PublicAPI.Shipped.txt** without understanding the breaking change implications. -- Add new public APIs to `PublicAPI.Unshipped.txt` files in the respective project directories. -- **Always check that all tests pass** - the test suite includes comprehensive validation of MediatR behaviors, analyzers, and integration scenarios. -- **Validation Scenarios**: After making changes, run these end-to-end validation steps: - 1. `cd src && dotnet clean && dotnet restore && dotnet build -c Debug` - 2. `dotnet test -c Debug --no-build --verbosity normal` - 3. Verify all 86 tests pass - 4. Check that no new analyzer warnings are introduced - 5. Ensure PublicAPI files are updated if needed - -## Common Tasks - -The following are outputs from frequently run commands. Reference them instead of viewing, searching, or running bash commands to save time. - -### Repository Structure -``` -. -├── .github/ # GitHub workflows and templates -├── src/ # All source code -│ ├── Workleap.Extensions.MediatR/ # Main library -│ ├── Workleap.Extensions.MediatR.ApplicationInsights/ # ApplicationInsights integration -│ ├── Workleap.Extensions.MediatR.Analyzers/ # Roslyn analyzers -│ ├── Workleap.Extensions.MediatR.Tests/ # Main library tests -│ ├── Workleap.Extensions.MediatR.Analyzers.Tests/ # Analyzer tests -│ └── Workleap.Extensions.MediatR.sln # Solution file -├── Build.ps1 # Main build script -├── README.md # Project documentation -├── global.json # .NET SDK version requirement (9.0.304) -└── Directory.Build.props # Shared MSBuild properties -``` - -### Key Project Components - -1. **Main Library** (`Workleap.Extensions.MediatR`): - - Multi-targets: netstandard2.0, net8.0 - - Provides MediatR extensions and behaviors - - Includes activity-based OpenTelemetry instrumentation - - High-performance logging with Debug level - - Data annotations support for request validation - -2. **ApplicationInsights Integration** (`Workleap.Extensions.MediatR.ApplicationInsights`): - - Separate NuGet package for Application Insights instrumentation - - Multi-targets: netstandard2.0, net8.0 - -3. **Roslyn Analyzers** (`Workleap.Extensions.MediatR.Analyzers`): - - Enforces CQRS naming conventions (GMDTR01-GMDTR13 rules) - - Embedded into main package during build - - Validates handler design patterns - -### Common Build Commands -```bash -# First restore (one-time setup - takes ~50 seconds) -cd src && dotnet restore - -# Subsequent restores (takes ~2 seconds) -cd src && dotnet restore - -# Debug build (development recommended - takes ~9 seconds) -cd src && dotnet build -c Debug - -# Run all tests (takes ~8 seconds if already built, ~17 seconds with build) -cd src && dotnet test -c Debug --no-build --verbosity normal - -# Run tests with automatic build (if you want to skip separate build step) -cd src && dotnet test -c Debug --verbosity normal - -# Clean and rebuild (for troubleshooting) -cd src && dotnet clean && dotnet build -c Debug - -# Check .NET version -dotnet --version -``` - -### PublicAPI Files -- `PublicAPI.Shipped.txt` - Contains all shipped public APIs (DO NOT MODIFY) -- `PublicAPI.Unshipped.txt` - Add new public APIs here before shipping - -### Analyzer Rules (GMDTR01-GMDTR13) -- GMDTR01-GMDTR06: Naming conventions for commands, queries, handlers, notifications -- GMDTR07-GMDTR13: Design patterns and best practices - -## Important Notes - -- **Release builds require GitVersion** which only works in CI environments with proper git context -- **Use Debug builds for local development** to avoid GitVersion issues -- **PowerShell 7.4+ is available** for running Build.ps1 if needed -- **Assembly signing is enabled** with Workleap.Extensions.MediatR.snk -- **InternalsVisibleTo** is configured between projects for testing -- **CI/CD is fully automated** - preview packages on main branch commits, stable releases on tags - -## Project Dependencies - -Key NuGet packages: -- MediatR 12.5.0 -- Microsoft.Extensions.Logging.Abstractions 8.0.0 -- Microsoft.CodeAnalysis.PublicApiAnalyzers 3.3.4 -- Workleap.DotNet.CodingStandards 1.1.3 (for style and analysis) - -## Troubleshooting - -- **"GitVersion failed"**: Use Debug build configuration instead of Release -- **"Framework not found"**: Install .NET 8.0 runtime for test execution -- **"Assembly not found"**: Run `dotnet restore` in src/ directory first -- **Tests failing**: Ensure both .NET 9.0.304 SDK and 8.0.8 runtime are installed +**Any code you commit SHOULD compile, and new and existing tests related to the change SHOULD pass.** + +You MUST make your best effort to ensure your changes satisfy those criteria before committing. If for any reason you were unable to build or test the changes, you MUST report that. You MUST NOT claim success unless all builds and tests pass as described above. + +Do not complete without checking the relevant code builds and relevant tests still pass after the last edits you make. Do not simply assume that your changes fix test failures you see, actually build and run those tests again to confirm. +Also, do not assume that tests pass just because you did not see any failures in your last test run; verify that all relevant tests were actually run. + +You MUST follow all code-formatting and naming conventions defined in [`.editorconfig`](/.editorconfig). + +In addition to the rules enforced by `.editorconfig`, you SHOULD: + +- Prefer file-scoped namespace declarations and single-line using directives. +- Ensure that the final return statement of a method is on its own line. +- Use pattern matching and switch expressions wherever possible. +- Use `nameof` instead of string literals when referring to member names. +- Always use `is null` or `is not null` instead of `== null` or `!= null`. +- Trust the C# null annotations and don't add null checks when the type system says a value cannot be null. +- Prefer `?.` if applicable (e.g. `scope?.Dispose()`). +- Use `ObjectDisposedException.ThrowIf` where applicable. +- When adding new unit tests, strongly prefer to add them to existing test code files rather than creating new code files. +- When running tests, if possible use filters and check test run counts, or look at test logs, to ensure they actually ran. +- Do not finish work with any tests commented out or disabled that were not previously commented out or disabled. +- Do not update `global.json` file +- When writing tests, do not emit "Act", "Arrange" or "Assert" comments. +- There should be no trailing whitespace in any lines. +- Add a blank line before XML documentation comments (`///`) when they follow other code (methods, properties, fields, etc.). \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b15e872..0106c49 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,7 +4,7 @@ on: pull_request: branches: ["main"] paths-ignore: ["*.md"] - + push: branches: - "renovate/**" @@ -35,6 +35,12 @@ jobs: feed-url: ${{ vars.GSOFTDEV_NUGET_SOURCE }} variables: ${{ toJSON(vars) }} + - uses: actions/setup-dotnet@v5 + with: + global-json-file: ./global.json + dotnet-version: | + 8.0.x + - run: ./Build.ps1 shell: pwsh env: diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml new file mode 100644 index 0000000..8b880be --- /dev/null +++ b/.github/workflows/copilot-setup-steps.yml @@ -0,0 +1,31 @@ +# See https://docs.github.com/en/copilot/customizing-copilot/customizing-the-development-environment-for-copilot-coding-agent +name: "Copilot Setup Steps" +on: + workflow_dispatch: + push: + paths: + - .github/workflows/copilot-setup-steps.yml + pull_request: + paths: + - .github/workflows/copilot-setup-steps.yml + + +jobs: + # The job MUST be called `copilot-setup-steps` or it will not be picked up by Copilot. + copilot-setup-steps: + runs-on: ubuntu-latest + + permissions: + contents: read + + steps: + - uses: actions/checkout@v6 + + - uses: actions/setup-dotnet@v5 + with: + global-json-file: './global.json' + dotnet-version: | + 8.0.x + + - name: Restore solution + run: dotnet restore src/ \ No newline at end of file diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 29bba29..8a1e505 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -33,6 +33,10 @@ jobs: secret-name: "nuget-org-workleap-api-key" - uses: actions/setup-dotnet@v5 + with: + global-json-file: ./global.json + dotnet-version: | + 8.0.x - run: ./Build.ps1 shell: pwsh diff --git a/.github/workflows/semgrep.yml b/.github/workflows/semgrep.yml index f3d069c..c935edd 100644 --- a/.github/workflows/semgrep.yml +++ b/.github/workflows/semgrep.yml @@ -10,6 +10,7 @@ on: jobs: call-workflow-semgrep: permissions: + actions: read contents: read security-events: write uses: workleap/wl-reusable-workflows/.github/workflows/reusable-semgrep-workflow.yml@main diff --git a/global.json b/global.json index 9783e56..69e101b 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "9.0.306", + "version": "10.0.100", "rollForward": "latestMinor", "allowPrerelease": false } diff --git a/src/Directory.Build.props b/src/Directory.Build.props index ea4d4ef..09750a5 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -11,7 +11,7 @@ - + all runtime; build; native; contentfiles; analyzers diff --git a/src/Workleap.Extensions.MediatR.Analyzers.Tests/Workleap.Extensions.MediatR.Analyzers.Tests.csproj b/src/Workleap.Extensions.MediatR.Analyzers.Tests/Workleap.Extensions.MediatR.Analyzers.Tests.csproj index d0eb9db..9d28e05 100644 --- a/src/Workleap.Extensions.MediatR.Analyzers.Tests/Workleap.Extensions.MediatR.Analyzers.Tests.csproj +++ b/src/Workleap.Extensions.MediatR.Analyzers.Tests/Workleap.Extensions.MediatR.Analyzers.Tests.csproj @@ -14,8 +14,8 @@ - - + + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Workleap.Extensions.MediatR.ApplicationInsights/Workleap.Extensions.MediatR.ApplicationInsights.csproj b/src/Workleap.Extensions.MediatR.ApplicationInsights/Workleap.Extensions.MediatR.ApplicationInsights.csproj index e4d70e0..1b9633a 100644 --- a/src/Workleap.Extensions.MediatR.ApplicationInsights/Workleap.Extensions.MediatR.ApplicationInsights.csproj +++ b/src/Workleap.Extensions.MediatR.ApplicationInsights/Workleap.Extensions.MediatR.ApplicationInsights.csproj @@ -14,7 +14,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Workleap.Extensions.MediatR.Tests/HostBuilderTests.cs b/src/Workleap.Extensions.MediatR.Tests/HostBuilderTests.cs index 5cf8ba0..e6d82af 100644 --- a/src/Workleap.Extensions.MediatR.Tests/HostBuilderTests.cs +++ b/src/Workleap.Extensions.MediatR.Tests/HostBuilderTests.cs @@ -6,6 +6,7 @@ using Microsoft.Extensions.Hosting; namespace Workleap.Extensions.MediatR.Tests; + public sealed class HostBuilderTests { [Fact] diff --git a/src/Workleap.Extensions.MediatR.Tests/Workleap.Extensions.MediatR.Tests.csproj b/src/Workleap.Extensions.MediatR.Tests/Workleap.Extensions.MediatR.Tests.csproj index adddb9b..3e11c15 100644 --- a/src/Workleap.Extensions.MediatR.Tests/Workleap.Extensions.MediatR.Tests.csproj +++ b/src/Workleap.Extensions.MediatR.Tests/Workleap.Extensions.MediatR.Tests.csproj @@ -16,8 +16,8 @@ - - + + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Workleap.Extensions.MediatR/Workleap.Extensions.MediatR.csproj b/src/Workleap.Extensions.MediatR/Workleap.Extensions.MediatR.csproj index 38114c1..308a47e 100644 --- a/src/Workleap.Extensions.MediatR/Workleap.Extensions.MediatR.csproj +++ b/src/Workleap.Extensions.MediatR/Workleap.Extensions.MediatR.csproj @@ -12,21 +12,21 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - + + + - +