Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 26 additions & 134 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -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.).
8 changes: 7 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:
pull_request:
branches: ["main"]
paths-ignore: ["*.md"]

push:
branches:
- "renovate/**"
Expand Down Expand Up @@ -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:
Expand Down
31 changes: 31 additions & 0 deletions .github/workflows/copilot-setup-steps.yml
Original file line number Diff line number Diff line change
@@ -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/
4 changes: 4 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/semgrep.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 1 addition & 1 deletion global.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"sdk": {
"version": "9.0.306",
"version": "10.0.100",
"rollForward": "latestMinor",
"allowPrerelease": false
}
Expand Down
2 changes: 1 addition & 1 deletion src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Workleap.DotNet.CodingStandards" Version="1.1.3">
<PackageReference Include="Workleap.DotNet.CodingStandards" Version="1.1.36">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@

<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Analyzer.Testing" Version="1.1.2" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.13.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="5.0.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

<ItemGroup>
<PackageReference Include="Microsoft.ApplicationInsights" Version="2.23.0" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.8" Condition="'$(TargetFramework)' == 'netstandard2.0'" />
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="10.0.0" Condition="'$(TargetFramework)' == 'netstandard2.0'" />
<PackageReference Include="Microsoft.CodeAnalysis.PublicApiAnalyzers" Version="3.3.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using Microsoft.Extensions.Hosting;

namespace Workleap.Extensions.MediatR.Tests;

public sealed class HostBuilderTests
{
[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Workleap.Extensions.Xunit" Version="1.1.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
<PackageReference Include="Workleap.Extensions.Xunit" Version="1.1.30" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.1.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,21 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="MediatR" Version="13.0.0" />
<PackageReference Include="MediatR" Version="13.1.0" />
<PackageReference Include="MediatR.Contracts" Version="2.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="2.3.0" />
<PackageReference Include="Microsoft.CodeAnalysis.PublicApiAnalyzers" Version="3.3.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.8" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.8" />
<PackageReference Include="System.Text.Json" Version="9.0.8" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="10.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.0" />
<PackageReference Include="System.Text.Json" Version="10.0.0" />
</ItemGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
<PackageReference Include="System.Diagnostics.DiagnosticSource" Version="9.0.8" />
<PackageReference Include="System.Diagnostics.DiagnosticSource" Version="10.0.0" />
</ItemGroup>

<ItemGroup>
Expand Down
Loading