Skip to content

Commit 372cd20

Browse files
committed
Add CPM, analyzers, SourceLink, format check, coverage report, SBOM, attestation, and community files
- Central Package Management via Directory.Packages.props - AnalysisLevel latest-recommended + EnforceCodeStyleInBuild - SourceLink properties (PublishRepositoryUrl, EmbedUntrackedSources) - NUKE Format target with dotnet format --verify-no-changes - GenerateDocumentationFile for packable projects (in targets) - Dynamic NuGet metadata from GITHUB_REPOSITORY env var - CoverageReport NUKE target using ReportGenerator - Migrate dotnet-tools.json to .config/ convention path - Add dotnet-reportgenerator-globaltool to tool manifest - SBOM generation (anchore/sbom-action) in release job - Artifact attestation (actions/attest-build-provenance) in release job - PR template and issue templates (bug-report, feature-request) - Fix Publish target missing DependsOn(Restore) - Fix sample code for new analyzer rules (static class, XML docs) - Add tests/.editorconfig to suppress CA1707 for test naming Made-with: Cursor
1 parent c605f03 commit 372cd20

18 files changed

Lines changed: 216 additions & 18 deletions
Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@
88
"docfx"
99
],
1010
"rollForward": false
11+
},
12+
"dotnet-reportgenerator-globaltool": {
13+
"version": "5.4.5",
14+
"commands": [
15+
"reportgenerator"
16+
],
17+
"rollForward": false
1118
}
1219
}
13-
}
20+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
name: Bug Report
2+
description: Report a bug or unexpected behavior
3+
labels: [bug]
4+
body:
5+
- type: textarea
6+
id: description
7+
attributes:
8+
label: Description
9+
description: A clear description of the bug.
10+
validations:
11+
required: true
12+
- type: textarea
13+
id: steps
14+
attributes:
15+
label: Steps to Reproduce
16+
description: Steps to reproduce the behavior.
17+
placeholder: |
18+
1. Run '...'
19+
2. See error
20+
validations:
21+
required: true
22+
- type: textarea
23+
id: expected
24+
attributes:
25+
label: Expected Behavior
26+
description: What you expected to happen.
27+
validations:
28+
required: true
29+
- type: input
30+
id: version
31+
attributes:
32+
label: Version
33+
description: Which version are you using?
34+
placeholder: e.g. 0.2.0
35+
- type: textarea
36+
id: environment
37+
attributes:
38+
label: Environment
39+
description: OS, .NET SDK version, and any other relevant details.
40+
placeholder: |
41+
OS: Ubuntu 24.04
42+
.NET SDK: 10.0.103
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
name: Feature Request
2+
description: Suggest a new feature or improvement
3+
labels: [enhancement]
4+
body:
5+
- type: textarea
6+
id: problem
7+
attributes:
8+
label: Problem
9+
description: What problem does this feature solve?
10+
validations:
11+
required: true
12+
- type: textarea
13+
id: solution
14+
attributes:
15+
label: Proposed Solution
16+
description: Describe the desired behavior or approach.
17+
validations:
18+
required: true
19+
- type: textarea
20+
id: alternatives
21+
attributes:
22+
label: Alternatives Considered
23+
description: Any alternative solutions or workarounds you have considered.

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
## Summary
2+
3+
<!-- Brief description of what this PR does and why -->
4+
5+
## Changes
6+
7+
-
8+
9+
## Test Plan
10+
11+
- [ ] Tests pass locally
12+
- [ ] No new warnings introduced

.github/workflows/ci.yml

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,13 +183,20 @@ jobs:
183183
- uses: actions/cache@v5
184184
with:
185185
path: ~/.nuget/packages
186-
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj', 'global.json', 'dotnet-tools.json') }}
186+
key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj', 'global.json', '.config/dotnet-tools.json') }}
187187
restore-keys: ${{ runner.os }}-nuget-
188188

189189
- name: Install .NET workloads
190190
if: matrix.workloads != ''
191191
run: dotnet workload install ${{ matrix.workloads }}
192192

193+
- name: Check code format
194+
if: matrix.runtime == 'linux-x64'
195+
shell: bash
196+
run: |
197+
chmod +x build.sh
198+
./build.sh Format
199+
193200
- name: Build and test
194201
if: runner.os != 'Windows'
195202
shell: bash
@@ -293,6 +300,8 @@ jobs:
293300
environment: release
294301
permissions:
295302
contents: write
303+
attestations: write
304+
id-token: write
296305
concurrency:
297306
group: release-tag-${{ needs.resolve-version.outputs.tag }}
298307
cancel-in-progress: false
@@ -392,6 +401,20 @@ jobs:
392401
shell: bash
393402
run: echo "::warning::NUGET_API_KEY not configured. Skipping NuGet push."
394403

404+
- name: Generate SBOM
405+
uses: anchore/sbom-action@v0
406+
with:
407+
artifact-name: sbom-spdx.json
408+
output-file: sbom-spdx.json
409+
format: spdx-json
410+
411+
- name: Attest build provenance
412+
uses: actions/attest-build-provenance@v2
413+
with:
414+
subject-path: |
415+
packages/*.nupkg
416+
installers/*.zip
417+
395418
- name: Create and push tag
396419
shell: bash
397420
run: |
@@ -432,7 +455,12 @@ jobs:
432455
exit 1
433456
fi
434457
435-
gh release create "$TAG" "${RELEASE_FILES[@]}" \
458+
SBOM_FILE=""
459+
if [ -f "sbom-spdx.json" ]; then
460+
SBOM_FILE="sbom-spdx.json"
461+
fi
462+
463+
gh release create "$TAG" "${RELEASE_FILES[@]}" $SBOM_FILE \
436464
--title "$RELEASE_NAME" \
437465
--generate-notes
438466
echo "Created release $TAG with ${#RELEASE_FILES[@]} assets"

Directory.Build.props

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,13 @@
55
<ImplicitUsings>enable</ImplicitUsings>
66
<Nullable>enable</Nullable>
77
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
8+
<AnalysisLevel>latest-recommended</AnalysisLevel>
9+
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
10+
<PublishRepositoryUrl>true</PublishRepositoryUrl>
11+
<EmbedUntrackedSources>true</EmbedUntrackedSources>
812
</PropertyGroup>
913

14+
1015
<!-- Explicit version: single source of truth for the entire solution.
1116
Bump this value via PR when preparing a new release. -->
1217
<PropertyGroup>

Directory.Build.targets

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,16 @@
55
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
66
</PropertyGroup>
77

8+
<!-- Generate XML documentation for packable projects only -->
9+
<PropertyGroup Condition="'$(IsPackable)' != 'false'">
10+
<GenerateDocumentationFile>true</GenerateDocumentationFile>
11+
</PropertyGroup>
12+
13+
<!-- Populate NuGet package metadata from GitHub environment variables -->
14+
<PropertyGroup Condition="'$(GITHUB_REPOSITORY)' != '' AND '$(RepositoryUrl)' == ''">
15+
<RepositoryUrl>https://github.com/$(GITHUB_REPOSITORY)</RepositoryUrl>
16+
<RepositoryType>git</RepositoryType>
17+
<PackageProjectUrl>https://github.com/$(GITHUB_REPOSITORY)</PackageProjectUrl>
18+
</PropertyGroup>
19+
820
</Project>

Directory.Packages.props

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<Project>
2+
3+
<PropertyGroup>
4+
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
5+
</PropertyGroup>
6+
7+
<ItemGroup>
8+
<!-- Build tooling -->
9+
<PackageVersion Include="Nuke.Common" Version="10.1.0" />
10+
<!-- Testing -->
11+
<PackageVersion Include="coverlet.collector" Version="8.0.0" />
12+
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.3.0" />
13+
<PackageVersion Include="xunit" Version="2.9.3" />
14+
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5" />
15+
</ItemGroup>
16+
17+
</Project>

build/BuildTask.Parameters.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,6 @@ partial class BuildTask
3535

3636
AbsolutePath ReleaseManifestFile => PackagesDirectory / "release-manifest.json";
3737
AbsolutePath BuildOutputsMarkerFile => ArtifactsDirectory / ".build-outputs" / "build-outputs.json";
38-
AbsolutePath ToolManifestFile => RootDirectory / "dotnet-tools.json";
38+
AbsolutePath ToolManifestFile => RootDirectory / ".config" / "dotnet-tools.json";
3939
AbsolutePath DirectoryBuildPropsFile => RootDirectory / "Directory.Build.props";
4040
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using System;
2+
using System.Linq;
3+
using Nuke.Common;
4+
using Nuke.Common.IO;
5+
using Nuke.Common.Tools.DotNet;
6+
using static Nuke.Common.Tools.DotNet.DotNetTasks;
7+
8+
partial class BuildTask
9+
{
10+
Target CoverageReport => _ => _
11+
.DependsOn(Test)
12+
.Executes(() =>
13+
{
14+
var coverageFiles = TestResultsDirectory.GlobFiles("**/coverage.cobertura.xml");
15+
if (!coverageFiles.Any())
16+
{
17+
Console.WriteLine("No coverage files found. Skipping report generation.");
18+
return;
19+
}
20+
21+
var reportDir = TestResultsDirectory / "coverage-report";
22+
var reports = string.Join(";", coverageFiles);
23+
24+
DotNet(
25+
$"reportgenerator " +
26+
$"-reports:{reports} " +
27+
$"-targetdir:{reportDir} " +
28+
$"-reporttypes:Cobertura;HtmlSummary " +
29+
$"-assemblyfilters:-*.Tests",
30+
workingDirectory: RootDirectory);
31+
32+
Console.WriteLine($"Coverage report generated at: {reportDir}");
33+
});
34+
}

0 commit comments

Comments
 (0)