Skip to content

Commit f873c1a

Browse files
authored
Enable InternalsVisibleTo for UnitTests in Package mode (#4300)
* Enable InternalsVisibleTo for test projects in Package mode * Pipeline: run unit tests in both Project and Package modes * Reverted some straggler leftover changes from previous attempts. * Addressed Copilot feedback.
1 parent 520b40b commit f873c1a

9 files changed

Lines changed: 200 additions & 87 deletions

File tree

build.proj

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,20 @@
259259
-p:SigningKeyPath="$(SigningKeyPath)"
260260
</SigningKeyPathArgument>
261261

262+
<!--
263+
TestSigningKeyPath
264+
Applies to: TestSqlClientUnit
265+
Description: Path to the key used to sign test assemblies. Required in Package mode when
266+
SigningKeyPath is set so that InternalsVisibleTo grants from signed driver
267+
assemblies can be fulfilled.
268+
Default value: [blank]
269+
Example: C:\path\to\sqlclient-test-key.snk
270+
-->
271+
<TestSigningKeyPath Condition="'$(TestSigningKeyPath)' == ''" />
272+
<TestSigningKeyPathArgument Condition="'$(TestSigningKeyPath)' != ''">
273+
-p:TestSigningKeyPath="$(TestSigningKeyPath)"
274+
</TestSigningKeyPathArgument>
275+
262276
<!--
263277
TestBlameTimeout
264278
Applies to: Test* targets
@@ -678,10 +692,6 @@
678692
<!-- TestSqlClientUnit: Runs unit tests for SqlClient -->
679693
<Target Name="TestSqlClientUnit">
680694
<PropertyGroup>
681-
<!--
682-
Note: This test exclusively uses project references, so neither ReferenceType nor any
683-
package version arguments are specified in this command.
684-
-->
685695
<LogFilePrefix>SqlClientUnit-$(OS)</LogFilePrefix>
686696
<LogFilePrefix Condition="'$(TestFramework)' != ''">$(LogFilePrefix)-$(TestFramework)</LogFilePrefix>
687697

@@ -692,6 +702,10 @@
692702
$(TestCodeCoverageArgument)
693703
$(TestFiltersArgument)
694704
$(TestFrameworkArgument)
705+
$(ReferenceTypeArgument)
706+
$(TestSigningKeyPathArgument)
707+
$(PackageVersionSqlClientArgument)
708+
$(PackageVersionSqlServerArgument)
695709
--results-directory "$(TestResultsFolderPath)"
696710
--logger:"trx;LogFilePrefix=$(LogFilePrefix)"
697711
</DotnetCommand>
@@ -862,7 +876,7 @@
862876
<PropertyGroup>
863877
<!--
864878
Note: This test exclusively uses project references, so neither ReferenceType nor any
865-
package version arguments are specified in this command.
879+
package version arguments are specified in this command.
866880
-->
867881
<LogFilePrefix>AbstractionsTests-$(OS)</LogFilePrefix>
868882
<LogFilePrefix Condition="'$(TestFramework)' != ''">$(LogFilePrefix)-$(TestFramework)</LogFilePrefix>

eng/pipelines/common/templates/steps/run-all-tests-step.yml

Lines changed: 86 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -79,51 +79,62 @@ steps:
7979
condition: succeededOrFailed()
8080

8181
- ${{if eq(parameters.operatingSystem, 'Windows')}}:
82-
- ${{if eq(parameters.referenceType, 'Project')}}:
83-
- task: DotNetCoreCLI@2
84-
displayName: 'Run Unit Tests ${{parameters.msbuildArchitecture }}'
85-
condition: and(eq(variables['setupSucceeded'], 'true'), succeededOrFailed())
86-
inputs:
87-
command: build
88-
projects: build.proj
89-
${{ if eq(parameters.msbuildArchitecture, 'x64') }}:
90-
arguments: >-
91-
-t:TestSqlClientUnit
92-
-p:TestFramework=${{ parameters.targetFramework }}
93-
-p:Configuration=${{ parameters.buildConfiguration }}
94-
-p:TestResultsFolderPath=TestResults
95-
${{ else }}: # x86
96-
arguments: >-
97-
-t:TestSqlClientUnit
98-
-p:TestFramework=${{ parameters.targetFramework }}
99-
-p:Configuration=${{ parameters.buildConfiguration }}
100-
-p:DotnetPath=${{ parameters.dotnetx86RootPath }}
101-
-p:TestResultsFolderPath=TestResults
82+
- task: DotNetCoreCLI@2
83+
displayName: 'Run Unit Tests ${{parameters.msbuildArchitecture }}'
84+
condition: and(eq(variables['setupSucceeded'], 'true'), succeededOrFailed())
85+
inputs:
86+
command: build
87+
projects: build.proj
88+
${{ if eq(parameters.msbuildArchitecture, 'x64') }}:
89+
arguments: >-
90+
-t:TestSqlClientUnit
91+
-p:TestFramework=${{ parameters.targetFramework }}
92+
-p:ReferenceType=${{ parameters.referenceType }}
93+
-p:Configuration=${{ parameters.buildConfiguration }}
94+
-p:PackageVersionSqlClient=${{ parameters.mdsPackageVersion }}
95+
-p:PackageVersionSqlServer=${{ parameters.sqlServerPackageVersion }}
96+
-p:TestResultsFolderPath=TestResults
97+
${{ else }}: # x86
98+
arguments: >-
99+
-t:TestSqlClientUnit
100+
-p:TestFramework=${{ parameters.targetFramework }}
101+
-p:ReferenceType=${{ parameters.referenceType }}
102+
-p:Configuration=${{ parameters.buildConfiguration }}
103+
-p:PackageVersionSqlClient=${{ parameters.mdsPackageVersion }}
104+
-p:PackageVersionSqlServer=${{ parameters.sqlServerPackageVersion }}
105+
-p:DotnetPath=${{ parameters.dotnetx86RootPath }}
106+
-p:TestResultsFolderPath=TestResults
102107
103-
- task: DotNetCoreCLI@2
104-
displayName: 'Run Flaky Unit Tests ${{parameters.msbuildArchitecture }}'
105-
condition: and(eq(variables['setupSucceeded'], 'true'), succeededOrFailed())
106-
inputs:
107-
command: build
108-
projects: build.proj
109-
${{ if eq(parameters.msbuildArchitecture, 'x64') }}:
110-
arguments: >-
111-
-t:TestSqlClientUnit
112-
-p:TestFramework=${{ parameters.targetFramework }}
113-
-p:Configuration=${{ parameters.buildConfiguration }}
114-
-p:TestFilters="category=flaky"
115-
-p:TestResultsFolderPath=TestResults
116-
-p:TestCodeCoverage=false
117-
${{ else }}: # x86
118-
arguments: >-
119-
-t:TestSqlClientUnit
120-
-p:TestFramework=${{ parameters.targetFramework }}
121-
-p:Configuration=${{ parameters.buildConfiguration }}
122-
-p:DotnetPath=${{ parameters.dotnetx86RootPath }}
123-
-p:TestFilters="category=flaky"
124-
-p:TestResultsFolderPath=TestResults
125-
-p:TestCodeCoverage=false
126-
continueOnError: true
108+
- task: DotNetCoreCLI@2
109+
displayName: 'Run Flaky Unit Tests ${{parameters.msbuildArchitecture }}'
110+
condition: and(eq(variables['setupSucceeded'], 'true'), succeededOrFailed())
111+
inputs:
112+
command: build
113+
projects: build.proj
114+
${{ if eq(parameters.msbuildArchitecture, 'x64') }}:
115+
arguments: >-
116+
-t:TestSqlClientUnit
117+
-p:TestFramework=${{ parameters.targetFramework }}
118+
-p:ReferenceType=${{ parameters.referenceType }}
119+
-p:Configuration=${{ parameters.buildConfiguration }}
120+
-p:PackageVersionSqlClient=${{ parameters.mdsPackageVersion }}
121+
-p:PackageVersionSqlServer=${{ parameters.sqlServerPackageVersion }}
122+
-p:TestFilters="category=flaky"
123+
-p:TestResultsFolderPath=TestResults
124+
-p:TestCodeCoverage=false
125+
${{ else }}: # x86
126+
arguments: >-
127+
-t:TestSqlClientUnit
128+
-p:TestFramework=${{ parameters.targetFramework }}
129+
-p:ReferenceType=${{ parameters.referenceType }}
130+
-p:Configuration=${{ parameters.buildConfiguration }}
131+
-p:PackageVersionSqlClient=${{ parameters.mdsPackageVersion }}
132+
-p:PackageVersionSqlServer=${{ parameters.sqlServerPackageVersion }}
133+
-p:DotnetPath=${{ parameters.dotnetx86RootPath }}
134+
-p:TestFilters="category=flaky"
135+
-p:TestResultsFolderPath=TestResults
136+
-p:TestCodeCoverage=false
137+
continueOnError: true
127138

128139
- task: DotNetCoreCLI@2
129140
displayName: 'Run Functional Tests ${{parameters.msbuildArchitecture }}'
@@ -261,33 +272,38 @@ steps:
261272
continueOnError: true
262273

263274
- ${{ else }}: # Linux or macOS
264-
- ${{if eq(parameters.referenceType, 'Project')}}:
265-
- task: DotNetCoreCLI@2
266-
displayName: 'Run Unit Tests'
267-
condition: and(eq(variables['setupSucceeded'], 'true'), succeededOrFailed())
268-
inputs:
269-
command: build
270-
projects: build.proj
271-
arguments: >-
272-
-t:TestSqlClientUnit
273-
-p:TestFramework=${{ parameters.targetFramework }}
274-
-p:Configuration=${{ parameters.buildConfiguration }}
275-
-p:TestResultsFolderPath=TestResults
275+
- task: DotNetCoreCLI@2
276+
displayName: 'Run Unit Tests'
277+
condition: and(eq(variables['setupSucceeded'], 'true'), succeededOrFailed())
278+
inputs:
279+
command: build
280+
projects: build.proj
281+
arguments: >-
282+
-t:TestSqlClientUnit
283+
-p:TestFramework=${{ parameters.targetFramework }}
284+
-p:ReferenceType=${{ parameters.referenceType }}
285+
-p:Configuration=${{ parameters.buildConfiguration }}
286+
-p:PackageVersionSqlClient=${{ parameters.mdsPackageVersion }}
287+
-p:PackageVersionSqlServer=${{ parameters.sqlServerPackageVersion }}
288+
-p:TestResultsFolderPath=TestResults
276289
277-
- task: DotNetCoreCLI@2
278-
displayName: 'Run Flaky Unit Tests'
279-
condition: and(eq(variables['setupSucceeded'], 'true'), succeededOrFailed())
280-
inputs:
281-
command: build
282-
projects: build.proj
283-
arguments: >-
284-
-t:TestSqlClientUnit
285-
-p:TestFramework=${{ parameters.targetFramework }}
286-
-p:Configuration=${{ parameters.buildConfiguration }}
287-
-p:TestFilters="category=flaky"
288-
-p:TestResultsFolderPath=TestResults
289-
-p:TestCodeCoverage=false
290-
continueOnError: true
290+
- task: DotNetCoreCLI@2
291+
displayName: 'Run Flaky Unit Tests'
292+
condition: and(eq(variables['setupSucceeded'], 'true'), succeededOrFailed())
293+
inputs:
294+
command: build
295+
projects: build.proj
296+
arguments: >-
297+
-t:TestSqlClientUnit
298+
-p:TestFramework=${{ parameters.targetFramework }}
299+
-p:ReferenceType=${{ parameters.referenceType }}
300+
-p:Configuration=${{ parameters.buildConfiguration }}
301+
-p:PackageVersionSqlClient=${{ parameters.mdsPackageVersion }}
302+
-p:PackageVersionSqlServer=${{ parameters.sqlServerPackageVersion }}
303+
-p:TestFilters="category=flaky"
304+
-p:TestResultsFolderPath=TestResults
305+
-p:TestCodeCoverage=false
306+
continueOnError: true
291307

292308
- task: DotNetCoreCLI@2
293309
displayName: 'Run Functional Tests'

src/Microsoft.Data.SqlClient/src/Microsoft.Data.SqlClient.csproj

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,26 @@
6262

6363
<!-- Strong name signing ============================================= -->
6464
<!-- Strong naming is being done in Directory.Build.props -->
65-
<!-- If we're not signing, we are permitted to expose our internals to tests. -->
65+
66+
<!-- Unsigned: expose internals to UnitTests in any reference mode. -->
6667
<ItemGroup Condition="'$(SigningKeyPath)' == ''">
6768
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleToAttribute">
6869
<_Parameter1>UnitTests</_Parameter1>
6970
</AssemblyAttribute>
7071
</ItemGroup>
7172

73+
<!--
74+
Signed + Package mode: expose internals to UnitTests signed with the test key.
75+
Signed + Project mode is intentionally omitted: production-signed assemblies should not
76+
grant internal access to test assemblies during local development. Tests that need internals
77+
in Project mode run unsigned; only the CI package-validation pipeline uses signed packages.
78+
-->
79+
<ItemGroup Condition="'$(SigningKeyPath)' != '' AND '$(ReferenceType)' == 'Package'">
80+
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleToAttribute">
81+
<_Parameter1>UnitTests, PublicKey=00240000048000001401000006020000002400005253413100080000010001003D19684676DA365F331D00CE7BD4B8EF03E74102F39A5681B40622703D68F0298ECACECC723D3FFC1EA9365AF4958578550EA1EBEEC084B0B3757F3762449F5365E872802A4B548056760764FAD062BFEE81ED26183109AD46810E7E6E965419D0A10473680144D20C1BFE1027A5F586CA987523C06F5C126C44EA7D4F51EB023867A9F294315F95775ACEFD2D678186919458DFCCB4DE2E9F53AEFC766C7CBCEC474ED21C1616E5A9414D366D91D121C39F5FE6641295ADC058EF3FB10593BCDE2E82D9F217C2634909EEF496CD53AE78ABBEA572B871D72EBFC5378205950ABA97C7CCC2B9635D96933D5F9C9624D71FF53EE2094CF3A6BD38534D66E414B7</_Parameter1>
82+
</AssemblyAttribute>
83+
</ItemGroup>
84+
7285
<!-- Build Output ==================================================== -->
7386
<PropertyGroup>
7487
<ArtifactPath>$(RepoRoot)artifacts/</ArtifactPath>

src/Microsoft.Data.SqlClient/tests/Common/Microsoft.Data.SqlClient.TestCommon.csproj

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@
1414
<IsTestProject>false</IsTestProject>
1515
</PropertyGroup>
1616

17+
<!-- Strong name signing ============================================= -->
18+
<!-- Sign with the test key so signed test assemblies can reference this project. -->
19+
<PropertyGroup Condition="'$(TestSigningKeyPath)' != ''">
20+
<SignAssembly>true</SignAssembly>
21+
<AssemblyOriginatorKeyFile>$(TestSigningKeyPath)</AssemblyOriginatorKeyFile>
22+
</PropertyGroup>
23+
1724
<!-- Target Frameworks =============================================== -->
1825
<PropertyGroup>
1926
<TargetFrameworks>net8.0;net9.0;net10.0</TargetFrameworks>
@@ -28,7 +35,10 @@
2835
<!-- References ====================================================== -->
2936
<!-- Test target reference -->
3037
<ItemGroup>
31-
<ProjectReference Include="$(RepoRoot)src/Microsoft.Data.SqlClient/src/Microsoft.Data.SqlClient.csproj" />
38+
<ProjectReference Include="$(RepoRoot)src/Microsoft.Data.SqlClient/src/Microsoft.Data.SqlClient.csproj"
39+
Condition="'$(ReferenceType)' != 'Package'" />
40+
<PackageReference Include="Microsoft.Data.SqlClient"
41+
Condition="'$(ReferenceType)' == 'Package'" />
3242
</ItemGroup>
3343

3444
<!-- References for netfx -->

src/Microsoft.Data.SqlClient/tests/UnitTests/Microsoft.Data.SqlClient.UnitTests.csproj

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,22 +36,53 @@
3636
</None>
3737
</ItemGroup>
3838

39+
<!-- Strong name signing ============================================= -->
40+
<!-- When a test signing key is provided, sign UnitTests so IVT from signed SqlClient works. -->
41+
<PropertyGroup Condition="'$(TestSigningKeyPath)' != ''">
42+
<SignAssembly>true</SignAssembly>
43+
<AssemblyOriginatorKeyFile>$(TestSigningKeyPath)</AssemblyOriginatorKeyFile>
44+
</PropertyGroup>
45+
3946
<!-- References ====================================================== -->
4047
<!-- Test target reference -->
41-
<ItemGroup>
42-
<!--
43-
The Unit Test project only supports ReferenceType = Project since it needs access to the
44-
internals of sibling packages.
45-
-->
48+
<ItemGroup Condition="'$(ReferenceType)' != 'Package'">
4649
<ProjectReference Include="$(RepoRoot)src/Microsoft.Data.SqlClient/src/Microsoft.Data.SqlClient.csproj" />
4750
<ProjectReference Include="$(RepoRoot)src/Microsoft.SqlServer.Server/Microsoft.SqlServer.Server.csproj" />
4851
</ItemGroup>
4952

50-
<Target Name="ValidateReferenceType"
51-
BeforeTargets="Restore;PrepareForBuild"
52-
Condition="'$(ReferenceType)' != 'Project'">
53-
<Error Text="Microsoft.Data.SqlClient.UnitTests.csproj only supports ReferenceType=Project." />
54-
</Target>
53+
<!--
54+
Package mode: Unit tests exercise internal types that only exist in the implementation assembly
55+
(runtimes/{rid}/lib/{tfm}/), not in the ref assembly (ref/{tfm}/). We exclude the ref
56+
compile asset and reference the runtime DLL directly so the compiler can see internals.
57+
58+
TODO: This is fragile, depending on our SqlClient NuGet package layout and supported TFMs. It
59+
is only necessary because we produce ref and not-supported assemblies and package them. By
60+
default, the compiler will use the ref assemblies if present, which we must explicitly override
61+
as explained above.
62+
-->
63+
<PropertyGroup Condition="'$(ReferenceType)' == 'Package'">
64+
<_SqlClientRid Condition="'$(OS)' != 'Windows_NT'">unix</_SqlClientRid>
65+
<_SqlClientRid Condition="'$(OS)' == 'Windows_NT'">win</_SqlClientRid>
66+
<!-- Map test TFM to the closest available package TFM (package ships net8.0/net9.0/net462) -->
67+
<_SqlClientPackageTfm Condition="'$(TargetFramework)' == 'net8.0'">net8.0</_SqlClientPackageTfm>
68+
<_SqlClientPackageTfm Condition="'$(TargetFramework)' == 'net462'">net462</_SqlClientPackageTfm>
69+
<_SqlClientPackageTfm Condition="'$(_SqlClientPackageTfm)' == ''">net9.0</_SqlClientPackageTfm>
70+
</PropertyGroup>
71+
<ItemGroup Condition="'$(ReferenceType)' == 'Package'">
72+
<!-- Brings in transitive dependencies and runtime deployment; ExcludeAssets="compile" prevents
73+
the compiler from using the ref assembly (which only contains public API surface).
74+
GeneratePathProperty="true" causes NuGet restore to emit $(PkgMicrosoft_Data_SqlClient)
75+
pointing to the extracted package folder in the global packages cache. -->
76+
<PackageReference Include="Microsoft.Data.SqlClient"
77+
GeneratePathProperty="true"
78+
ExcludeAssets="compile" />
79+
<!-- Compile against the implementation assembly so the compiler can resolve internal types
80+
exposed via InternalsVisibleTo. The path uses $(PkgMicrosoft_Data_SqlClient) generated
81+
above to locate the runtime DLL inside the NuGet package layout. -->
82+
<Reference Include="Microsoft.Data.SqlClient"
83+
HintPath="$(PkgMicrosoft_Data_SqlClient)/runtimes/$(_SqlClientRid)/lib/$(_SqlClientPackageTfm)/Microsoft.Data.SqlClient.dll" />
84+
<PackageReference Include="Microsoft.SqlServer.Server" />
85+
</ItemGroup>
5586

5687
<!-- References for netframework -->
5788
<ItemGroup Condition="'$(TargetFramework)' == 'net462'">

src/Microsoft.Data.SqlClient/tests/tools/Microsoft.Data.SqlClient.TestUtilities/Microsoft.Data.SqlClient.TestUtilities.csproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22
<PropertyGroup>
33
<TargetFramework>netstandard2.0</TargetFramework>
44
</PropertyGroup>
5+
6+
<!-- Strong name signing ============================================= -->
7+
<!-- Sign with the test key so signed test assemblies can reference this project. -->
8+
<PropertyGroup Condition="'$(TestSigningKeyPath)' != ''">
9+
<SignAssembly>true</SignAssembly>
10+
<AssemblyOriginatorKeyFile>$(TestSigningKeyPath)</AssemblyOriginatorKeyFile>
11+
</PropertyGroup>
12+
513
<Target Name="CopyConfig" BeforeTargets="Compile">
614
<Copy SourceFiles="config.default.json" DestinationFiles="config.json" Condition="!Exists('config.json')" />
715
</Target>

src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS.EndPoint/TDS.EndPoint.csproj

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,15 @@
33
<RootNamespace>Microsoft.SqlServer.TDS.EndPoint</RootNamespace>
44
<AssemblyName>Microsoft.SqlServer.TDS.EndPoint</AssemblyName>
55
<TargetFramework>netstandard2.0</TargetFramework>
6+
</PropertyGroup>
7+
8+
<!-- Sign when a test key is provided so signed test assemblies can reference this. -->
9+
<PropertyGroup Condition="'$(TestSigningKeyPath)' != ''">
10+
<SignAssembly>true</SignAssembly>
11+
<AssemblyOriginatorKeyFile>$(TestSigningKeyPath)</AssemblyOriginatorKeyFile>
12+
</PropertyGroup>
13+
14+
<PropertyGroup>
615
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
716
</PropertyGroup>
817
<ItemGroup>

src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS.Servers/TDS.Servers.csproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@
44
<AssemblyName>Microsoft.SqlServer.TDS.Servers</AssemblyName>
55
<TargetFramework>netstandard2.0</TargetFramework>
66
</PropertyGroup>
7+
8+
<!-- Sign when a test key is provided so signed test assemblies can reference this. -->
9+
<PropertyGroup Condition="'$(TestSigningKeyPath)' != ''">
10+
<SignAssembly>true</SignAssembly>
11+
<AssemblyOriginatorKeyFile>$(TestSigningKeyPath)</AssemblyOriginatorKeyFile>
12+
</PropertyGroup>
713
<ItemGroup>
814
<ProjectReference Include="$(RepoRoot)src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS.EndPoint/TDS.EndPoint.csproj" />
915
<ProjectReference Include="$(RepoRoot)src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS/TDS.csproj" />

src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS/TDS.csproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,10 @@
44
<AssemblyName>Microsoft.SqlServer.TDS</AssemblyName>
55
<TargetFramework>netstandard2.0</TargetFramework>
66
</PropertyGroup>
7+
8+
<!-- Sign when a test key is provided so signed test assemblies can reference this. -->
9+
<PropertyGroup Condition="'$(TestSigningKeyPath)' != ''">
10+
<SignAssembly>true</SignAssembly>
11+
<AssemblyOriginatorKeyFile>$(TestSigningKeyPath)</AssemblyOriginatorKeyFile>
12+
</PropertyGroup>
713
</Project>

0 commit comments

Comments
 (0)