Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 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
34 changes: 12 additions & 22 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,33 +11,25 @@ Workleap.DotNet.CodingStandards is a NuGet package that provides coding standard

1. **Install required dependencies:**
```bash
# Install .NET 9.0 SDK (required by global.json)
# Install .NET 10.0 SDK (required by global.json)
wget https://dotnetcli.azureedge.net/dotnet/Sdk/9.0.304/dotnet-sdk-9.0.304-linux-x64.tar.gz
sudo mkdir -p /usr/share/dotnet9
sudo tar zxf dotnet-sdk-9.0.304-linux-x64.tar.gz -C /usr/share/dotnet9
export PATH="/usr/share/dotnet9:$PATH"
export DOTNET_ROOT="/usr/share/dotnet9"

# Install .NET 8.0 runtime (required for tests)
wget https://dotnetcli.azureedge.net/dotnet/Runtime/8.0.12/dotnet-runtime-8.0.12-linux-x64.tar.gz
sudo tar zxf dotnet-runtime-8.0.12-linux-x64.tar.gz -C /usr/share/dotnet9

# Install Mono and NuGet.exe (required for packaging and tests)
sudo apt-get install -y mono-complete
wget https://dist.nuget.org/win-x86-commandline/latest/nuget.exe
sudo mv nuget.exe /usr/local/bin/
echo '#!/bin/bash
exec mono /usr/local/bin/nuget.exe "$@"' | sudo tee /usr/local/bin/nuget
sudo chmod +x /usr/local/bin/nuget


# Install PowerShell (if not available)
# PowerShell is already available in GitHub Actions
```

2. **Restore tools and build components:**
```bash
dotnet tool restore # Installs GitVersion - takes 5 seconds

# Generate analyzer configuration files - takes 15 seconds. NEVER CANCEL.
dotnet run --project=tools/ConfigurationFilesGenerator/ConfigurationFilesGenerator.csproj --configuration Release --verbosity normal
```
Expand All @@ -51,7 +43,7 @@ Workleap.DotNet.CodingStandards is a NuGet package that provides coding standard
```bash
# Get version (may fail on feature branches - use manual version instead)
VERSION=$(dotnet dotnet-gitversion /output json /showvariable SemVer 2>/dev/null || echo "1.1.25-dev")

# Pack the package
nuget pack Workleap.DotNet.CodingStandards.nuspec -OutputDirectory .output -Version $VERSION -ForceEnglishOutput
```
Expand All @@ -61,7 +53,7 @@ Workleap.DotNet.CodingStandards is a NuGet package that provides coding standard
# NEVER CANCEL: Full build takes 60+ seconds
export PATH="/usr/share/dotnet9:/usr/local/bin:$PATH"
export DOTNET_ROOT="/usr/share/dotnet9"

dotnet tool restore
dotnet run --project=tools/ConfigurationFilesGenerator/ConfigurationFilesGenerator.csproj --configuration Release
VERSION=$(dotnet dotnet-gitversion /output json /showvariable SemVer 2>/dev/null || echo "1.1.25-dev")
Expand Down Expand Up @@ -92,7 +84,7 @@ pwsh --version # Should show PowerShell 7.x
```bash
# Should complete in ~15 seconds and show analyzer packages being processed
dotnet run --project=tools/ConfigurationFilesGenerator/ConfigurationFilesGenerator.csproj --configuration Release

# Verify generated files exist
ls -la src/files/analyzers/
# Should show: Analyzer.*.editorconfig files and manual_rules.editorconfig
Expand Down Expand Up @@ -138,7 +130,7 @@ dotnet test --configuration Release # Verify all tests pass
src/
├── build/ # MSBuild .props/.targets files
├── buildTransitive/ # Transitive MSBuild files
├── buildMultiTargeting/ # Multi-targeting MSBuild files
├── buildMultiTargeting/ # Multi-targeting MSBuild files
└── files/
├── *.editorconfig # Static configuration files
├── BannedSymbols.txt # Banned API definitions
Expand All @@ -150,23 +142,21 @@ tests/
```

### Dependencies and Requirements
- **.NET 9.0 SDK:** Required for building (specified in global.json)
- **.NET 10.0 SDK:** Required for building (specified in global.json)
- **.NET 8.0 Runtime:** Required for running tests (test project targets net8.0)
- **PowerShell:** Required for Build.ps1 script
- **Mono + NuGet.exe:** Required for packaging and test fixtures
- **GitVersion:** .NET tool for automatic versioning

### Timing Expectations
**CRITICAL: Never cancel these operations. Set timeouts appropriately:**
- Tool restore: ~5 seconds
- ConfigurationFilesGenerator: ~15 seconds
- Full build: ~20 seconds
- Full build: ~20 seconds
- Tests: ~32 seconds (14 test cases)
- Full CI pipeline: ~60 seconds total

### Build Failures and Solutions
- **"SDK not found" error:** Ensure .NET 9.0 SDK is installed and in PATH
- **"nuget command not found":** Install mono and create nuget wrapper script
- **"SDK not found" error:** Ensure .NET 10.0 SDK is installed and in PATH
- **Test failures with runtime errors:** Ensure .NET 8.0 runtime is available
- **GitVersion errors on feature branches:** Use manual version instead

Expand All @@ -186,6 +176,6 @@ Tests use ProjectBuilder helper to:

## References
- Build script: Build.ps1 (PowerShell)
- CI workflow: .github/workflows/ci.yml
- CI workflow: .github/workflows/ci.yml
- Package definition: Workleap.DotNet.CodingStandards.nuspec
- Test project: tests/Workleap.DotNet.CodingStandards.Tests/
18 changes: 10 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,24 +36,26 @@ jobs:
feed-url: ${{ vars.GSOFTDEV_NUGET_SOURCE }}
variables: ${{ toJSON(vars) }}

- name: Install Mono
shell: bash
run: |
apt-get update
apt-get install -y mono-complete

- uses: NuGet/setup-nuget@v2

- run: ./Build.ps1
shell: pwsh
env:
NUGET_SOURCE: ${{ vars.GSOFTDEV_NUGET_SOURCE }}

- name: Upload NuGet package
uses: actions/upload-artifact@v5
if: always()
with:
name: nuget-package
path: .output/**/*
include-hidden-files: true
if-no-files-found: error

linearb:
needs: [main]
uses: workleap/wl-reusable-workflows/.github/workflows/linearb-deployment.yml@main
with:
environment: development
cortexEntityIdOrTag: service-wl-dotnet-codingstandards
permissions:
id-token: write
contents: read
8 changes: 0 additions & 8 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,6 @@ jobs:

- uses: actions/setup-dotnet@v5

- name: Install Mono
shell: bash
run: |
apt-get update
apt-get install -y mono-complete

- uses: NuGet/setup-nuget@v2

- run: ./Build.ps1
shell: pwsh
env:
Expand Down
4 changes: 2 additions & 2 deletions Build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ Process {
Exec { & dotnet run --project=tools/ConfigurationFilesGenerator/ConfigurationFilesGenerator.csproj --configuration Release }

# Pack using NuGet.exe
Exec { & nuget pack Workleap.DotNet.CodingStandards.nuspec -OutputDirectory $outputDir -Version $version -ForceEnglishOutput }
Exec { & dotnet pack Workleap.DotNet.CodingStandards.csproj --output $outputDir -p:NuspecProperties=version=$version }

# Run tests
Exec { & dotnet test --configuration Release --logger "console;verbosity=detailed" }
Exec { & dotnet test wl-dotnet-codingstandards.slnx --configuration Release --logger "console;verbosity=detailed" }

# Push to a NuGet feed if the environment variables are set
if (($null -ne $env:NUGET_SOURCE) -and ($null -ne $env:NUGET_API_KEY)) {
Expand Down
13 changes: 13 additions & 0 deletions Workleap.DotNet.CodingStandards.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<NoBuild>true</NoBuild>
<IncludeBuildOutput>false</IncludeBuildOutput>
<TargetFramework>netstandard2.0</TargetFramework>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<NoWarn>NU5128</NoWarn>
<NuSpecFile>Workleap.DotNet.CodingStandards.nuspec</NuSpecFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Remove="Workleap.DotNet.CodingStandards" />
</ItemGroup>
</Project>
4 changes: 2 additions & 2 deletions Workleap.DotNet.CodingStandards.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
<copyright>Copyright © Workleap</copyright>
<repository type="git" url="$RepositoryUrl$" commit="$RepositoryCommit$" branch="$RepositoryBranch$" />
<dependencies>
<dependency id="Meziantou.Analyzer" version="2.0.201" />
<dependency id="Meziantou.Analyzer" version="2.0.254" />
<dependency id="Microsoft.CodeAnalysis.BannedApiAnalyzers" version="4.14.0" />
<dependency id="Microsoft.CodeAnalysis.NetAnalyzers" version="9.0.0" />
<dependency id="Microsoft.CodeAnalysis.NetAnalyzers" version="10.0.100" />
<dependency id="StyleCop.Analyzers" version="1.2.0-beta.556" />
</dependencies>
</metadata>
Expand Down
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
49 changes: 47 additions & 2 deletions src/files/analyzers/Analyzer.Meziantou.Analyzer.editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ dotnet_diagnostic.MA0051.severity = none
# Enabled: True, Severity: suggestion
dotnet_diagnostic.MA0052.severity = suggestion

# MA0053: Make class sealed
# MA0053: Make class or record sealed
# Help link: https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0053.md
# Enabled: True, Severity: suggestion
dotnet_diagnostic.MA0053.severity = none
Expand Down Expand Up @@ -527,7 +527,7 @@ dotnet_diagnostic.MA0105.severity = none
# Enabled: True, Severity: suggestion
dotnet_diagnostic.MA0106.severity = none

# MA0107: Do not use culture-sensitive object.ToString
# MA0107: Do not use object.ToString
# Help link: https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0107.md
# Enabled: False, Severity: suggestion
dotnet_diagnostic.MA0107.severity = none
Expand Down Expand Up @@ -842,3 +842,48 @@ dotnet_diagnostic.MA0168.severity = none
# Enabled: True, Severity: warning
dotnet_diagnostic.MA0169.severity = none

# MA0170: Type cannot be used as an attribute argument
# Help link: https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0170.md
# Enabled: False, Severity: warning
dotnet_diagnostic.MA0170.severity = none

# MA0171: Use pattern matching instead of HasValue for Nullable<T> check
# Help link: https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0171.md
# Enabled: False, Severity: suggestion
dotnet_diagnostic.MA0171.severity = none

# MA0172: Both sides of the logical operation are identical
# Help link: https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0172.md
# Enabled: False, Severity: warning
dotnet_diagnostic.MA0172.severity = none

# MA0173: Use LazyInitializer.EnsureInitialize
# Help link: https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0173.md
# Enabled: True, Severity: suggestion
dotnet_diagnostic.MA0173.severity = suggestion

# MA0174: Record should use explicit 'class' keyword
# Help link: https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0174.md
# Enabled: False, Severity: suggestion
dotnet_diagnostic.MA0174.severity = none

# MA0175: Record should not use explicit 'class' keyword
# Help link: https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0175.md
# Enabled: False, Severity: suggestion
dotnet_diagnostic.MA0175.severity = none

# MA0176: Optimize guid creation
# Help link: https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0176.md
# Enabled: True, Severity: suggestion
dotnet_diagnostic.MA0176.severity = suggestion

# MA0177: Use single-line XML comment syntax when possible
# Help link: https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0177.md
# Enabled: False, Severity: suggestion
dotnet_diagnostic.MA0177.severity = none

# MA0178: Use TimeSpan.Zero instead of TimeSpan.FromXXX(0)
# Help link: https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0178.md
# Enabled: True, Severity: suggestion
dotnet_diagnostic.MA0178.severity = suggestion

Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,11 @@ dotnet_diagnostic.IDE0340.severity = silent
# Enabled: True, Severity: silent
dotnet_diagnostic.IDE0350.severity = silent

# IDE0360: Simplify property accessor
# Help link: https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0360
# Enabled: True, Severity: silent
dotnet_diagnostic.IDE0360.severity = silent

# IDE1005: Delegate invocation can be simplified.
# Help link: https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide1005
# Enabled: True, Severity: silent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,11 @@ dotnet_diagnostic.CA1514.severity = suggestion
# Enabled: False, Severity: warning
dotnet_diagnostic.CA1515.severity = none

# CA1516: Use cross-platform intrinsics
# Help link: https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1516
# Enabled: True, Severity: suggestion
dotnet_diagnostic.CA1516.severity = suggestion

# CA1700: Do not name enum values 'Reserved'
# Help link: https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1700
# Enabled: False, Severity: warning
Expand Down Expand Up @@ -801,6 +806,21 @@ dotnet_diagnostic.CA1871.severity = suggestion
# Enabled: True, Severity: suggestion
dotnet_diagnostic.CA1872.severity = suggestion

# CA1873: Avoid potentially expensive logging
# Help link: https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1873
# Enabled: True, Severity: suggestion
dotnet_diagnostic.CA1873.severity = suggestion

# CA1874: Use 'Regex.IsMatch'
# Help link: https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1874
# Enabled: True, Severity: suggestion
dotnet_diagnostic.CA1874.severity = suggestion

# CA1875: Use 'Regex.Count'
# Help link: https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1875
# Enabled: True, Severity: suggestion
dotnet_diagnostic.CA1875.severity = suggestion

# CA2000: Dispose objects before losing scope
# Help link: https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2000
# Enabled: False, Severity: warning
Expand Down Expand Up @@ -889,6 +909,21 @@ dotnet_diagnostic.CA2021.severity = warning
# Enabled: True, Severity: warning
dotnet_diagnostic.CA2022.severity = warning

# CA2023: Invalid braces in message template
# Help link: https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2023
# Enabled: True, Severity: warning
dotnet_diagnostic.CA2023.severity = warning

# CA2024: Do not use 'StreamReader.EndOfStream' in async methods
# Help link: https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2024
# Enabled: True, Severity: warning
dotnet_diagnostic.CA2024.severity = warning

# CA2025: Do not pass 'IDisposable' instances into unawaited tasks
# Help link: https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2025
# Enabled: False, Severity: warning
dotnet_diagnostic.CA2025.severity = none

# CA2100: Review SQL queries for security vulnerabilities
# Help link: https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2100
# Enabled: False, Severity: warning
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,10 @@ public async Task PdbShouldBeEmbedded_Dotnet_Build()

project.AddFile("Sample.cs", """
namespace Foo;
public static class Sample { }

public static class Sample
{
}
""");
var data = await project.BuildAndGetOutput(["--configuration", "Release"]);

Expand Down Expand Up @@ -249,15 +252,18 @@ public async Task PdbShouldBeEmbedded_Dotnet_Pack()

project.AddFile("Sample.cs", """
namespace Foo;
public static class Sample { }

public static class Sample
{
}
""");
var data = await project.PackAndGetOutput(["--configuration", "Release"]);

var extractedPath = Path.Combine(project.RootFolder, "extracted");
var files = Directory.GetFiles(Path.Combine(project.RootFolder, "bin", "Release"));
Assert.Single(files); // Only the .nupkg should be generated
var nupkg = files.Single(f => f.EndsWith(".nupkg", StringComparison.OrdinalIgnoreCase));
ZipFile.ExtractToDirectory(nupkg, extractedPath);
await ZipFile.ExtractToDirectoryAsync(nupkg, extractedPath);

var outputFiles = Directory.GetFiles(extractedPath, "*", SearchOption.AllDirectories);
await AssertPdbIsEmbedded(outputFiles);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
namespace Workleap.DotNet.CodingStandards.Tests.Helpers;

internal static class SharedHttpClient
{
public static HttpClient Instance { get; } = CreateHttpClient();
Expand Down
Loading
Loading