-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
Copy pathValidatePackageTask.cs
196 lines (165 loc) · 7.75 KB
/
ValidatePackageTask.cs
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
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using Microsoft.Build.Framework;
using Microsoft.DotNet.ApiCompatibility.Logging;
using Microsoft.NET.Build.Tasks;
using NuGet.Frameworks;
namespace Microsoft.DotNet.ApiCompat.Task
{
/// <summary>
/// ApiCompat's ValidatePackage msbuild frontend.
/// This task provides the functionality to compare package assets based on given inputs.
/// </summary>
public class ValidatePackageTask : TaskBase
{
// Important: Keep properties exposed in sync with the CLI frontend.
/// <summary>
/// The path to the package to inspect.
/// </summary>
[Required]
public string? PackageTargetPath { get; set; }
/// <summary>
/// The path to the roslyn assemblies that should be loaded.
/// </summary>
[Required]
public string? RoslynAssembliesPath { get; set; }
/// <summary>
/// A runtime graph that can be provided for package asset selection.
/// </summary>
public string? RuntimeGraph { get; set; }
/// <summary>
/// If true, includes both internal and public API.
/// </summary>
public bool RespectInternals { get; set; }
/// <summary>
/// Enables rule to check that attributes match.
/// </summary>
public bool EnableRuleAttributesMustMatch { get; set; }
/// <summary>
/// Set of files with types in DocId format of which attributes to exclude.
/// </summary>
public string[]? ExcludeAttributesFiles { get; set; }
/// <summary>
/// Enables rule to check that the parameter names between public methods do not change.
/// </summary>
public bool EnableRuleCannotChangeParameterName { get; set; }
/// <summary>
/// If true, performs api compatibility checks on the package assets.
/// </summary>
public bool RunApiCompat { get; set; } = true;
/// <summary>
/// Validates api compatibility in strict mode for contract and implementation assemblies for all compatible target frameworks.
/// </summary>
public bool EnableStrictModeForCompatibleTfms { get; set; } = true;
/// <summary>
/// Validates api compatibility in strict mode for assemblies that are compatible based on their target framework.
/// </summary>
public bool EnableStrictModeForCompatibleFrameworksInPackage { get; set; }
/// <summary>
/// Validates api compatibility in strict mode for package baseline checks.
/// </summary>
public bool EnableStrictModeForBaselineValidation { get; set; }
/// <summary>
/// The path to the baseline package that acts as the contract to inspect.
/// </summary>
public string? BaselinePackageTargetPath { get; set; }
/// <summary>
/// If true, generates a suppression file that contains the api compatibility errors.
/// </summary>
public bool GenerateSuppressionFile { get; set; }
/// <summary>
/// If true, preserves unnecessary suppressions when re-generating the suppression file.
/// </summary>
public bool PreserveUnnecessarySuppressions { get; set; }
/// <summary>
/// If true, permits unnecessary suppressions in the suppression file.
/// </summary>
public bool PermitUnnecessarySuppressions { get; set; }
/// <summary>
/// The path to suppression files. If provided, the suppressions are read and stored.
/// </summary>
public string[]? SuppressionFiles { get; set; }
/// <summary>
/// The path to the suppression output file that is written to, when <see cref="GenerateSuppressionFile"/> is true.
/// </summary>
public string? SuppressionOutputFile { get; set; }
/// <summary>
/// A NoWarn string contains the error codes that should be ignored.
/// </summary>
public string? NoWarn { get; set; }
/// <summary>
/// Assembly references grouped by target framework, for the assets inside the package.
/// </summary>
public ITaskItem[]? PackageAssemblyReferences { get; set; }
/// <summary>
/// Assembly references grouped by target framework, for the assets inside the baseline package.
/// </summary>
public ITaskItem[]? BaselinePackageAssemblyReferences { get; set; }
/// <summary>
/// A set of target frameworks to ignore from the baseline package.
/// The framework string must exactly match the folder name in the baseilne package.
/// </summary>
public string[]? BaselinePackageFrameworksToIgnore { get; set; }
public override bool Execute()
{
RoslynResolver roslynResolver = RoslynResolver.Register(RoslynAssembliesPath!);
try
{
return base.Execute();
}
finally
{
roslynResolver.Unregister();
}
}
protected override void ExecuteCore()
{
SuppressibleMSBuildLog logFactory(ISuppressionEngine suppressionEngine) => new(Log, suppressionEngine);
ValidatePackage.Run(logFactory,
GenerateSuppressionFile,
PreserveUnnecessarySuppressions,
PermitUnnecessarySuppressions,
SuppressionFiles,
SuppressionOutputFile,
NoWarn,
RespectInternals,
EnableRuleAttributesMustMatch,
ExcludeAttributesFiles,
EnableRuleCannotChangeParameterName,
PackageTargetPath!,
RunApiCompat,
EnableStrictModeForCompatibleTfms,
EnableStrictModeForCompatibleFrameworksInPackage,
EnableStrictModeForBaselineValidation,
BaselinePackageTargetPath,
RuntimeGraph,
ParsePackageAssemblyReferences(PackageAssemblyReferences),
ParsePackageAssemblyReferences(BaselinePackageAssemblyReferences),
BaselinePackageFrameworksToIgnore);
}
private static Dictionary<NuGetFramework, IEnumerable<string>>? ParsePackageAssemblyReferences(ITaskItem[]? packageAssemblyReferences)
{
if (packageAssemblyReferences is null || packageAssemblyReferences.Length == 0)
return null;
Dictionary<NuGetFramework, IEnumerable<string>> packageAssemblyReferencesDict = new(packageAssemblyReferences.Length);
foreach (ITaskItem taskItem in packageAssemblyReferences)
{
string targetFrameworkMoniker = taskItem.GetMetadata("TargetFrameworkMoniker");
string targetPlatformMoniker = taskItem.GetMetadata("TargetPlatformMoniker");
string referencePath = taskItem.GetMetadata("ReferencePath");
// The TPM is null when the assembly doesn't target a platform.
if (targetFrameworkMoniker == string.Empty || referencePath == string.Empty)
continue;
NuGetFramework nuGetFramework = NuGetFramework.ParseComponents(targetFrameworkMoniker, targetPlatformMoniker);
// Skip duplicate frameworks which could be passed in when using TFM aliases.
if (packageAssemblyReferencesDict.ContainsKey(nuGetFramework))
{
continue;
}
string[] references = referencePath.Split(',');
packageAssemblyReferencesDict.Add(nuGetFramework, references);
}
return packageAssemblyReferencesDict;
}
}
}