-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathDirectory.Build.targets
More file actions
206 lines (192 loc) · 16.1 KB
/
Copy pathDirectory.Build.targets
File metadata and controls
206 lines (192 loc) · 16.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
<Project>
<!-- Imported after the project body and the SDK targets, so conditions here see final property values. -->
<PropertyGroup Label="Package readme by convention" Condition="'$(IsPackable)' == 'true'">
<PackageReadmeFile Condition="'$(PackageReadmeFile)' == ''">README.md</PackageReadmeFile>
</PropertyGroup>
<ItemGroup Label="Package readme by convention" Condition="'$(IsPackable)' == 'true'">
<!-- Update, not Include: the SDK's default globs already add README.md as a None item. -->
<None Update="README.md" Pack="true" PackagePath="/"/>
</ItemGroup>
<!-- CS1591 only: IDE0005 needs the documentation file, but test code does not document its public members. -->
<PropertyGroup Label="No XML doc requirement under tests/" Condition="'$(IsTestTree)' == 'true'">
<NoWarn>$(NoWarn);CS1591</NoWarn>
</PropertyGroup>
<Target Name="CheatEngineSdkRequireProjectReadme" BeforeTargets="BeforeBuild">
<Error Condition="!Exists('$(MSBuildProjectDirectory)/README.md')"
Code="CESDK9001"
Text="$(MSBuildProjectName) has no README.md next to its project file."/>
</Target>
<!--
A component built against a newer Roslyn than the consumer's compiler does not load there (CS9057). No local build
catches a bumped pin because the SDK named in global.json bundles the same Roslyn, so this target compares the
two copies of the pin.
-->
<Target Name="CheatEngineSdkCheckRoslynPin" BeforeTargets="BeforeBuild" Condition="'$(IsRoslynComponent)' == 'true'">
<PropertyGroup>
<_CheatEngineSdkRoslynPin>@(PackageVersion->WithMetadataValue('Identity', 'Microsoft.CodeAnalysis.CSharp')->'%(Version)')</_CheatEngineSdkRoslynPin>
<_CheatEngineSdkWorkspacesPin>@(PackageVersion->WithMetadataValue('Identity', 'Microsoft.CodeAnalysis.CSharp.Workspaces')->'%(Version)')</_CheatEngineSdkWorkspacesPin>
</PropertyGroup>
<Error Condition="'$(_CheatEngineSdkRoslynPin)' != '$(RoslynComponentFloor)' or '$(_CheatEngineSdkWorkspacesPin)' != '$(RoslynComponentFloor)'"
Code="CESDK9002"
Text="Directory.Packages.props pins Microsoft.CodeAnalysis.CSharp '$(_CheatEngineSdkRoslynPin)' and Workspaces '$(_CheatEngineSdkWorkspacesPin)', expected '$(RoslynComponentFloor)'. Restore the pin, or raise it together with RoslynComponentFloor in eng/RoslynComponent.props."/>
</Target>
<!--
PublicApiAnalyzers only tracks a project whose PublicAPI files exist; without them RS0016/RS0017 never fire and a
public change goes unnoticed. Every shipping library therefore carries both files (eng/Shipping.props).
-->
<Target Name="CheatEngineSdkRequirePublicApiFiles"
BeforeTargets="BeforeBuild"
Condition="$(_CheatEngineSdkFolder.StartsWith('libs/'))">
<Error Condition="!Exists('$(MSBuildProjectDirectory)/PublicAPI.Shipped.txt') or !Exists('$(MSBuildProjectDirectory)/PublicAPI.Unshipped.txt')"
Code="CESDK9003"
Text="$(MSBuildProjectName) needs PublicAPI.Shipped.txt and PublicAPI.Unshipped.txt next to its project file: every shipping library tracks its public API."/>
</Target>
<!--
Version and content are locked for every project (audit ch.21 exit criteria): no project may opt out of its
packages.lock.json or of Central Package Management, including projects outside the solution.
-->
<Target Name="CheatEngineSdkRequireLockedPackages" BeforeTargets="BeforeBuild">
<Error Condition="'$(RestorePackagesWithLockFile)' != 'true' or '$(ManagePackageVersionsCentrally)' != 'true'"
Code="CESDK9005"
Text="$(MSBuildProjectName) builds with RestorePackagesWithLockFile '$(RestorePackagesWithLockFile)' and ManagePackageVersionsCentrally '$(ManagePackageVersionsCentrally)'. Every project restores centrally managed versions against a committed packages.lock.json: remove the override and regenerate with 'dotnet restore --force-evaluate'."/>
</Target>
<!--
The analysis level is pinned next to the exact SDK (global.json rollForward: disable), so the set of CA/IDE rules
and their severities only changes in a reviewed commit. A project-level or command-line AnalysisLevel would silently
widen or narrow that set for one project.
-->
<Target Name="CheatEngineSdkCheckAnalysisLevelPin" BeforeTargets="BeforeBuild">
<Error Condition="'$(AnalysisLevel)' != '$(_CheatEngineSdkPinnedAnalysisLevel)'"
Code="CESDK9004"
Text="$(MSBuildProjectName) builds with AnalysisLevel '$(AnalysisLevel)', but the repository pins '$(_CheatEngineSdkPinnedAnalysisLevel)'. Remove the override, or raise the pin in Directory.Build.props together with global.json."/>
</Target>
<!--
NuGet audit policy (Directory.Build.props, "NuGet audit"). Lists are compared as items after splitting on ';', ','
and whitespace, so NU19031 never matches NU1903 and 'nu1903' does.
-->
<Target Name="CheatEngineSdkCheckNuGetAuditPolicy" BeforeTargets="BeforeBuild">
<PropertyGroup>
<_CheatEngineSdkAuditRequiredErrors>$(_CheatEngineSdkNuGetAuditBlockingCodes)</_CheatEngineSdkAuditRequiredErrors>
<_CheatEngineSdkAuditRequiredErrors Condition="'$(AuditPipeline)' == 'true'">$(_CheatEngineSdkNuGetAuditCodes)</_CheatEngineSdkAuditRequiredErrors>
</PropertyGroup>
<ItemGroup>
<_CheatEngineSdkAuditRequiredError Include="$([MSBuild]::Unescape($(_CheatEngineSdkAuditRequiredErrors.ToUpperInvariant())))"/>
<_CheatEngineSdkAuditWeakened Include="$([MSBuild]::Unescape($([System.Text.RegularExpressions.Regex]::Replace('$(NoWarn);$(WarningsNotAsErrors)', '[\s,;]+', ';').ToUpperInvariant())))"/>
<_CheatEngineSdkAuditAsError Include="$([MSBuild]::Unescape($([System.Text.RegularExpressions.Regex]::Replace('$(WarningsAsErrors)', '[\s,;]+', ';').ToUpperInvariant())))"/>
<!-- Intersection: weakened codes that must stay errors. -->
<_CheatEngineSdkAuditWeakenedOther Include="@(_CheatEngineSdkAuditWeakened)" Exclude="@(_CheatEngineSdkAuditRequiredError)"/>
<_CheatEngineSdkAuditWeakenedRequired Include="@(_CheatEngineSdkAuditWeakened)" Exclude="@(_CheatEngineSdkAuditWeakenedOther)"/>
<!-- Difference: codes that must be errors but are missing from WarningsAsErrors. -->
<_CheatEngineSdkAuditMissingError Include="@(_CheatEngineSdkAuditRequiredError)" Exclude="@(_CheatEngineSdkAuditAsError)"/>
</ItemGroup>
<Error Condition="'$(NuGetAudit)' != 'true' or '$(NuGetAuditMode)' != 'all' or '$(NuGetAuditLevel)' != 'low'"
Code="CESDK9009"
Text="$(MSBuildProjectName) restores with NuGetAudit '$(NuGetAudit)', NuGetAuditMode '$(NuGetAuditMode)' and NuGetAuditLevel '$(NuGetAuditLevel)'. The repository audits every package (direct and transitive) at every severity: true, all, low."/>
<Error Condition="'@(_CheatEngineSdkAuditWeakenedRequired)' != ''"
Code="CESDK9009"
Text="$(MSBuildProjectName) lists @(_CheatEngineSdkAuditWeakenedRequired, ', ') in NoWarn or WarningsNotAsErrors. High and critical advisories (and, in the AuditPipeline run, every audit code) must fail the restore: fix or upgrade the package, or add a justified, expiring NuGetAuditSuppress in Directory.Build.props."/>
<Error Condition="'@(_CheatEngineSdkAuditMissingError)' != ''"
Code="CESDK9009"
Text="$(MSBuildProjectName) does not list @(_CheatEngineSdkAuditMissingError, ', ') in WarningsAsErrors. Append to WarningsAsErrors instead of replacing it."/>
</Target>
<!--
Advisory suppressions are reviewed exceptions: declared only in Directory.Build.props, each with a Justification and
an Expires date (yyyy-MM-dd). The dedicated audit run fails once a suppression has expired; ordinary builds never
fail on the calendar. Runs inside restore, where the suppressions take effect.
-->
<Target Name="CheatEngineSdkCheckNuGetAuditSuppressions"
BeforeTargets="CollectNuGetAuditSuppressions"
Condition="'@(NuGetAuditSuppress)' != ''">
<PropertyGroup>
<_CheatEngineSdkAuditSuppressionsFile>$([MSBuild]::NormalizePath('$(RepoRoot)', 'Directory.Build.props'))</_CheatEngineSdkAuditSuppressionsFile>
<_CheatEngineSdkUtcToday>$([System.DateTime]::UtcNow.ToString('yyyyMMdd'))</_CheatEngineSdkUtcToday>
</PropertyGroup>
<Error Condition="'%(NuGetAuditSuppress.DefiningProjectFullPath)' != '$(_CheatEngineSdkAuditSuppressionsFile)'"
Code="CESDK9009"
Text="NuGetAuditSuppress '%(NuGetAuditSuppress.Identity)' is declared in '%(NuGetAuditSuppress.DefiningProjectFullPath)'. Declare advisory suppressions only in Directory.Build.props."/>
<Error Condition="'%(NuGetAuditSuppress.Justification)' == '' or !$([System.Text.RegularExpressions.Regex]::IsMatch('%(NuGetAuditSuppress.Expires)', '^\d{4}-\d{2}-\d{2}$'))"
Code="CESDK9009"
Text="NuGetAuditSuppress '%(NuGetAuditSuppress.Identity)' needs Justification metadata and Expires metadata in yyyy-MM-dd form (found '%(NuGetAuditSuppress.Expires)')."/>
<Error Condition="'$(AuditPipeline)' == 'true' and $([System.String]::Copy('%(NuGetAuditSuppress.Expires)').Replace('-', '')) < $(_CheatEngineSdkUtcToday)"
Code="CESDK9009"
Text="NuGetAuditSuppress '%(NuGetAuditSuppress.Identity)' expired on %(NuGetAuditSuppress.Expires). Re-review the advisory: fix it, or renew the suppression with a new justification and date."/>
</Target>
<!--
Package validation against the last published release (src/CheatEngine.SDK/CheatEngine.SDK.csproj):
https://learn.microsoft.com/dotnet/fundamentals/apicompat/package-validation/baseline-version-validator
Compatibility mode only (strict mode would reject additions). CI must validate against the committed
CompatibilitySuppressions.xml and the downloaded baseline: it never regenerates, relaxes or bypasses them. Only the
integrator regenerates the file, locally, with -p:ApiCompatGenerateSuppressionFile=true.
-->
<Target Name="CheatEngineSdkCheckPackageValidation"
BeforeTargets="GenerateNuspec"
Condition="'$(IsPackable)' == 'true'">
<ItemGroup>
<_CheatEngineSdkPackNoWarnCode Include="$([MSBuild]::Unescape($([System.Text.RegularExpressions.Regex]::Replace('$(NoWarn)', '[\s,;]+', ';').ToUpperInvariant())))"/>
<!-- ApiCompat (CPxxxx) and package validation (PKVxxx) diagnostics honor NoWarn, which would hide a break wholesale. -->
<_CheatEngineSdkSilencedCompatCode Include="@(_CheatEngineSdkPackNoWarnCode)"
Condition="$([System.String]::Copy('%(Identity)').StartsWith('CP')) or $([System.String]::Copy('%(Identity)').StartsWith('PKV'))"/>
</ItemGroup>
<Error Condition="'@(_CheatEngineSdkSilencedCompatCode)' != ''"
Code="CESDK9006"
Text="$(MSBuildProjectName) silences package validation diagnostics @(_CheatEngineSdkSilencedCompatCode, ', ') through NoWarn. Declare each intentional break in CompatibilitySuppressions.xml instead."/>
<Error Condition="'$(EnablePackageValidation)' != 'true' or '$(PackageValidationBaselineVersion)' == '' or '$(EnableStrictModeForBaselineValidation)' == 'true'"
Code="CESDK9006"
Text="$(MSBuildProjectName) packs with EnablePackageValidation '$(EnablePackageValidation)', PackageValidationBaselineVersion '$(PackageValidationBaselineVersion)' and EnableStrictModeForBaselineValidation '$(EnableStrictModeForBaselineValidation)'. Every pack is validated against the last published release in compatibility mode: true, a released version, not true."/>
<Error Condition="'$(ContinuousIntegrationBuild)' == 'true' and ('$(ApiCompatGenerateSuppressionFile)' == 'true' or '$(GenerateCompatibilitySuppressionFile)' == 'true' or '$(ApiCompatPermitUnnecessarySuppressions)' == 'true' or '$(DisablePackageBaselineValidation)' == 'true' or '$(RunApiCompat)' == 'false' or '$(PackageValidationBaselinePath)' != '')"
Code="CESDK9006"
Text="A CI pack of $(MSBuildProjectName) must validate against the committed CompatibilitySuppressions.xml and the downloaded $(PackageValidationBaselineVersion) baseline, but ApiCompatGenerateSuppressionFile='$(ApiCompatGenerateSuppressionFile)', GenerateCompatibilitySuppressionFile='$(GenerateCompatibilitySuppressionFile)', ApiCompatPermitUnnecessarySuppressions='$(ApiCompatPermitUnnecessarySuppressions)', DisablePackageBaselineValidation='$(DisablePackageBaselineValidation)', RunApiCompat='$(RunApiCompat)', PackageValidationBaselinePath='$(PackageValidationBaselinePath)'. Only the integrator regenerates the suppression file, locally."/>
</Target>
<!--
SemVer: a package that declares intentional breaks against its baseline (baseline suppressions in
CompatibilitySuppressions.xml) must be on a higher major line than that baseline. The version comes from MinVer, so
this runs after it.
-->
<Target Name="CheatEngineSdkCheckBreakingChangeMajor"
BeforeTargets="GenerateNuspec"
DependsOnTargets="MinVer"
Condition="'$(IsPackable)' == 'true' and '$(PackageValidationBaselineVersion)' != ''">
<PropertyGroup>
<_CheatEngineSdkSuppressionFile>$([MSBuild]::NormalizePath('$(MSBuildProjectDirectory)', 'CompatibilitySuppressions.xml'))</_CheatEngineSdkSuppressionFile>
<_CheatEngineSdkDeclaresBreaks>false</_CheatEngineSdkDeclaresBreaks>
<_CheatEngineSdkDeclaresBreaks Condition="Exists('$(_CheatEngineSdkSuppressionFile)') and $([System.IO.File]::ReadAllText('$(_CheatEngineSdkSuppressionFile)').Contains('<IsBaselineSuppression>true</IsBaselineSuppression>'))">true</_CheatEngineSdkDeclaresBreaks>
<_CheatEngineSdkPackageMajor>$(PackageVersion.Split('-')[0].Split('.')[0])</_CheatEngineSdkPackageMajor>
<_CheatEngineSdkBaselineMajor>$(PackageValidationBaselineVersion.Split('-')[0].Split('.')[0])</_CheatEngineSdkBaselineMajor>
</PropertyGroup>
<Error Condition="'$(_CheatEngineSdkDeclaresBreaks)' == 'true' and $(_CheatEngineSdkPackageMajor) <= $(_CheatEngineSdkBaselineMajor)"
Code="CESDK9007"
Text="$(MSBuildProjectName) $(PackageVersion) declares intentional breaks against $(PackageValidationBaselineVersion) in CompatibilitySuppressions.xml: intentional breaks against $(PackageValidationBaselineVersion) require a new major; raise MinVerMinimumMajorMinor (Directory.Build.props) or tag a new major."/>
</Target>
<!--
Every package embeds an SPDX SBOM (Microsoft.Sbom.Targets, GenerateSBOM), locally and in CI alike, so the release
attests the same inventory a developer sees.
-->
<Target Name="CheatEngineSdkRequireSbom"
BeforeTargets="GenerateNuspec"
Condition="'$(IsPackable)' == 'true'">
<Error Condition="'$(GenerateSBOM)' != 'true' or '@(PackageReference->WithMetadataValue('Identity', 'Microsoft.Sbom.Targets'))' == ''"
Code="CESDK9008"
Text="$(MSBuildProjectName) packs without an SBOM (GenerateSBOM '$(GenerateSBOM)'). Reference Microsoft.Sbom.Targets with PrivateAssets="all" and set GenerateSBOM to true unconditionally."/>
</Target>
<!--
Microsoft.Sbom.Targets defaults SbomGenerationPackageVersion to $(Version) at evaluation, but MinVer sets the version
during execution; without this the SBOM would describe version 1.0.0. Runs after MinVer, before the SBOM target.
-->
<Target Name="CheatEngineSdkAlignSbomPackageVersion"
BeforeTargets="GenerateSbomTarget"
DependsOnTargets="MinVer"
Condition="'$(IsPackable)' == 'true' and '$(GenerateSBOM)' == 'true'">
<PropertyGroup>
<SbomGenerationPackageVersion>$(PackageVersion)</SbomGenerationPackageVersion>
</PropertyGroup>
</Target>
<!-- The release path never suppresses: a stable (non-prerelease) package version cannot be packed while any suppression exists. -->
<Target Name="CheatEngineSdkRefuseAuditSuppressionsOnRelease"
BeforeTargets="GenerateNuspec"
DependsOnTargets="MinVer"
Condition="'$(IsPackable)' == 'true' and '@(NuGetAuditSuppress)' != ''">
<Error Condition="!$(PackageVersion.Contains('-'))"
Code="CESDK9009"
Text="$(MSBuildProjectName) packs the release version $(PackageVersion) while NuGetAuditSuppress items exist (@(NuGetAuditSuppress, ', ')). Remove every suppression before a release."/>
</Target>
</Project>