diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
index b4723cf34..d8771c0f0 100644
--- a/.github/ISSUE_TEMPLATE.md
+++ b/.github/ISSUE_TEMPLATE.md
@@ -1,10 +1,13 @@
## Description
> **IMPORTANT**: if the defect is reproduced only in a workflow from within the Visual Studio IDE then do not report the issue here - instead, please report it using Visual Studio's "Send Feedback" option that can be accessed from the Help menu OR using this link https://developercommunity.visualstudio.com.
>
+> **IMPORTANT**: Before posting an issue, please search the repository for similar ones. It might have been solved or reported already.
+>
> For a defect specific to the MSTest V2 test framework, describe the issue you've observed.
## Steps to reproduce
> What steps can reproduce the defect?
+>
> Please share the setup, sample project, target platform (desktop, core, uap)
## Expected behavior
@@ -15,5 +18,7 @@
## Environment
> Please share additional details about the test environment.
-> Operating system, Build version of vstest.console, Package version of MSTest
-> framework and adapter
+> - Operating system
+> - Build version of vstest.console
+> - Package version of MSTest framework and adapter
+> - Other installed packages and their versions on the test project
diff --git a/.gitignore b/.gitignore
index 2688b7eb7..7ef5c066f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -88,6 +88,7 @@ ehthumbs.db
packages
artifacts
Tools
+.dotnet
# ===========================
# Tools
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
index 958979430..f9ba8cf65 100644
--- a/CODE_OF_CONDUCT.md
+++ b/CODE_OF_CONDUCT.md
@@ -1,2 +1,9 @@
-### Microsoft Open Source Code of Conduct
-This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
+# Microsoft Open Source Code of Conduct
+
+This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
+
+Resources:
+
+- [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
+- [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
+- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 0730c476c..757d10b19 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -2,13 +2,13 @@
Welcome, and thank you for your interest in contributing. There are many ways to contribute:
- [Submit issues](https://github.com/Microsoft/testfx/issues) and help verify fixes as they are checked in.
- Review the [source code changes](https://github.com/Microsoft/testfx/pulls).
-- [Contribute features and fixes](https://github.com/Microsoft/testfx-docs/blob/master/docs/contribute.md).
+- [Contribute features and fixes](https://github.com/Microsoft/testfx-docs/blob/main/docs/contribute.md).
- Contribute to the [documentation](https://github.com/Microsoft/testfx-docs).
### Building
If you want to understand how **testfx** works or want to debug an issue, you'll want to get the source, build it, and run it locally. **testfx** can be built from within Visual Studio or from the CLI.
-- [Building with Visual Studio](https://github.com/Microsoft/testfx-docs/blob/master/docs/contribute.md#building-with-visual-studiovs)
-- [Building with CLI](https://github.com/Microsoft/testfx-docs/blob/master/docs/contribute.md#building-with-command-linecli)
+- [Building with Visual Studio](https://github.com/Microsoft/testfx-docs/blob/main/docs/contribute.md#building-with-visual-studiovs)
+- [Building with CLI](https://github.com/Microsoft/testfx-docs/blob/main/docs/contribute.md#building-with-command-linecli)
### Thank You!
Your contributions to open source, large or small, make projects like this possible. Thank you for taking the time to contribute.
diff --git a/Directory.Build.props b/Directory.Build.props
new file mode 100644
index 000000000..262a72352
--- /dev/null
+++ b/Directory.Build.props
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/Directory.Build.targets b/Directory.Build.targets
new file mode 100644
index 000000000..58e8fd573
--- /dev/null
+++ b/Directory.Build.targets
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/Nuget.config b/NuGet.config
similarity index 75%
rename from Nuget.config
rename to NuGet.config
index bdab0c8cc..38283aac6 100644
--- a/Nuget.config
+++ b/NuGet.config
@@ -1,15 +1,21 @@
-
+
+
+
+
-
+
+
+
+
-
-
+
+
@@ -18,8 +24,8 @@
-
-
+
+
diff --git a/README.md b/README.md
index bc5fbc253..5a15c2357 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@ This is a fully supported, open source and cross-platform implementation of the
### Build status
-[![Build Status](https://dev.azure.com/dnceng/public/_apis/build/status/Microsoft/testfx/microsoft.testfx.ci?branchName=master)](https://dev.azure.com/dnceng/public/_build/latest?definitionId=937&branchName=master)
+[![Build Status](https://dev.azure.com/dnceng/public/_apis/build/status/Microsoft/testfx/microsoft.testfx.ci?branchName=main)](https://dev.azure.com/dnceng/public/_build/latest?definitionId=937&branchName=main)
### Latest Builds
| | Framework | Adapter |
@@ -19,22 +19,22 @@ This is a fully supported, open source and cross-platform implementation of the
There are many ways to contribute to testfx
- [Submit issues](https://github.com/Microsoft/testfx/issues) and help verify fixes as they are checked in.
- Review the [source code changes](https://github.com/Microsoft/testfx/pulls).
-- [Contribute features and fixes](https://github.com/Microsoft/testfx-docs/blob/master/docs/contribute.md).
+- [Contribute features and fixes](https://github.com/Microsoft/testfx-docs/blob/main/docs/contribute.md).
- Contribute to the [documentation](https://github.com/Microsoft/testfx-docs).
### Building
testfx can be built from within Visual Studio or from the CLI.
-- [Building with Visual Studio](https://github.com/Microsoft/testfx-docs/blob/master/docs/contribute.md#building-with-visual-studiovs)
-- [Building with CLI](https://github.com/Microsoft/testfx-docs/blob/master/docs/contribute.md#building-with-command-linecli)
+- [Building with Visual Studio](https://github.com/Microsoft/testfx-docs/blob/main/docs/contribute.md#building-with-visual-studiovs)
+- [Building with CLI](https://github.com/Microsoft/testfx-docs/blob/main/docs/contribute.md#building-with-command-linecli)
### Microsoft Open Source Code of Conduct
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
### License
-testfx platform is licensed under the [MIT license](https://github.com/Microsoft/testfx/blob/master/LICENSE)
+testfx platform is licensed under the [MIT license](https://github.com/Microsoft/testfx/blob/main/LICENSE)
### Issue Tracking
-Please see [issue tracking](https://github.com/Microsoft/testfx-docs/blob/master/issuetracking.md) for a description of the workflow we use to process issues.
+Please see [issue tracking](https://github.com/Microsoft/testfx-docs/blob/main/issuetracking.md) for a description of the workflow we use to process issues.
### Roadmap
-For information on shipped and upcoming features/enhancements please refer to our [Releases](https://github.com/Microsoft/testfx-docs/blob/master/docs/releases.md) and [Quarterly Checkin reports](https://github.com/Microsoft/testfx-docs/tree/master/Quarterly%20Checkins).
+For information on shipped and upcoming features/enhancements please refer to our [Releases](https://github.com/Microsoft/testfx-docs/blob/main/docs/releases.md) and [Quarterly Checkin reports](https://github.com/Microsoft/testfx-docs/tree/main/Quarterly%20Checkins).
diff --git a/TestFx.sln b/TestFx.sln
index 183aebced..1d10ff71e 100644
--- a/TestFx.sln
+++ b/TestFx.sln
@@ -119,6 +119,10 @@ EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlatformServices.Portable.Unit.Tests", "test\UnitTests\PlatformServices.Portable.Unit.Tests\PlatformServices.Portable.Unit.Tests.csproj", "{E3C630FE-AF89-4C95-B1B9-2409B1107208}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlatformServices.Universal.Unit.Tests", "test\UnitTests\PlatformServices.Universal.Unit.Tests\PlatformServices.Universal.Unit.Tests.csproj", "{FA7C719F-A400-45AF-8091-7C23435617A8}"
+ ProjectSection(ProjectDependencies) = postProject
+ {DF131865-84EE-4540-8112-E88ACEBDEA09} = {DF131865-84EE-4540-8112-E88ACEBDEA09}
+ {5D153CAA-80C2-4551-9549-6C406FCEEFB1} = {5D153CAA-80C2-4551-9549-6C406FCEEFB1}
+ EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MSTest.Core.Unit.Tests", "test\UnitTests\MSTest.Core.Unit.Tests\MSTest.Core.Unit.Tests.csproj", "{0A4A76DD-FEE1-4D04-926B-38E1A24A7ED2}"
EndProject
@@ -136,10 +140,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "stylecop", "stylecop", "{FE
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "targets", "targets", "{F60B647A-E14C-48AF-9BD6-89F44EB60115}"
ProjectSection(SolutionItems) = preProject
- scripts\build\TestFx.Loc.targets = scripts\build\TestFx.Loc.targets
- scripts\build\TestFx.Settings.targets = scripts\build\TestFx.Settings.targets
+ scripts\build\TestFx.Loc.props = scripts\build\TestFx.Loc.props
+ scripts\build\TestFx.props = scripts\build\TestFx.props
scripts\build\TestFx.targets = scripts\build\TestFx.targets
- scripts\build\TestFx.Versions.targets = scripts\build\TestFx.Versions.targets
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "scripts", "scripts", "{BCF525B1-E67F-486D-B091-06A8BB8A2793}"
@@ -184,6 +187,20 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TimeoutTestProjectNetCore",
EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharpTestProject", "test\E2ETests\TestAssets\FSharpTestProject\FSharpTestProject.fsproj", "{E5E58613-82FC-44CD-B75F-4F1C7ED52D0D}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DiscoveryAndExecutionTests", "test\E2ETests\DiscoveryAndExecutionTests\DiscoveryAndExecutionTests.csproj", "{EEE57613-6424-4A1C-9635-B73768F2146D}"
+ ProjectSection(ProjectDependencies) = postProject
+ {E5E58613-82FC-44CD-B75F-4F1C7ED52D0D} = {E5E58613-82FC-44CD-B75F-4F1C7ED52D0D}
+ {98BA6D2C-1F3D-4636-8E1D-D4932B7A253D} = {98BA6D2C-1F3D-4636-8E1D-D4932B7A253D}
+ {A7EA583B-A2B0-47DA-A058-458F247C7575} = {A7EA583B-A2B0-47DA-A058-458F247C7575}
+ {BBC99A6B-4490-49DD-9C12-AF2C1E95576E} = {BBC99A6B-4490-49DD-9C12-AF2C1E95576E}
+ {B0FCE474-14BC-449A-91EA-A433342C0D63} = {B0FCE474-14BC-449A-91EA-A433342C0D63}
+ {4004757A-0080-4410-B90A-6169B20F151B} = {4004757A-0080-4410-B90A-6169B20F151B}
+ {7FB80AAB-7123-4416-B6CD-8D3D69AA83F1} = {7FB80AAB-7123-4416-B6CD-8D3D69AA83F1}
+ {5A4967CD-B527-4D43-81C2-4CA90EE10222} = {5A4967CD-B527-4D43-81C2-4CA90EE10222}
+ {9C1219E0-E775-47F9-9236-63F03F774801} = {9C1219E0-E775-47F9-9236-63F03F774801}
+ {7252D9E3-267D-442C-96BC-C73AEF3241D6} = {7252D9E3-267D-442C-96BC-C73AEF3241D6}
+ EndProjectSection
+EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Extension.WinUI", "src\TestFramework\Extension.WinUI\Extension.WinUI.csproj", "{23B9D9A2-4AEE-47E6-97B5-060DF21539FB}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NetCore", "NetCore", "{D11C6664-1C4E-48F0-AA92-7F5BADC6F82C}"
@@ -191,11 +208,21 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NetCore", "NetCore", "{D11C
src\Adapter\Build\NetCore\MSTest.TestAdapter.props = src\Adapter\Build\NetCore\MSTest.TestAdapter.props
EndProjectSection
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PlatformServices.WinUI", "src\Adapter\PlatformServices.WinUI\PlatformServices.WinUI.csproj", "{F4E2876F-6E42-4DCF-B629-041A9DF7C579}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "WinUI", "WinUI", "{35D010CC-CDF2-4115-BCFB-E2E3D21C1055}"
+ ProjectSection(SolutionItems) = preProject
+ src\Adapter\Build\WinUI\MSTest.TestAdapter.props = src\Adapter\Build\WinUI\MSTest.TestAdapter.props
+ src\Adapter\Build\WinUI\MSTest.TestAdapter.targets = src\Adapter\Build\WinUI\MSTest.TestAdapter.targets
+ EndProjectSection
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReferencedProjectFromDataSourceTest", "test\E2ETests\TestAssets\ReferencedProjectFromDataSourceTest\ReferencedProjectFromDataSourceTest.csproj", "{6B4DE65C-4162-4C52-836A-8F9FA901814A}"
+EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\Adapter\PlatformServices.Shared\PlatformServices.Shared.projitems*{2177c273-ae07-43b3-b87a-443e47a23c5a}*SharedItemsImports = 13
- src\TestFramework\Extension.Shared\Extension.Shared.projitems*{272ca5e1-8e81-4825-9e47-86cce02f700d}*SharedItemsImports = 13
src\TestFramework\Extension.Shared\Extension.Shared.projitems*{23b9d9a2-4aee-47e6-97b5-060df21539fb}*SharedItemsImports = 5
+ src\TestFramework\Extension.Shared\Extension.Shared.projitems*{272ca5e1-8e81-4825-9e47-86cce02f700d}*SharedItemsImports = 13
src\TestFramework\Extension.Shared\Extension.Shared.projitems*{df131865-84ee-4540-8112-e88acebdea09}*SharedItemsImports = 4
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -351,12 +378,12 @@ Global
{B0FCE474-14BC-449A-91EA-A433342C0D63}.Debug|x86.Build.0 = Debug|Any CPU
{B0FCE474-14BC-449A-91EA-A433342C0D63}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B0FCE474-14BC-449A-91EA-A433342C0D63}.Release|Any CPU.Build.0 = Release|Any CPU
- {B0FCE474-14BC-449A-91EA-A433342C0D63}.Release|ARM.ActiveCfg = Debug|Any CPU
- {B0FCE474-14BC-449A-91EA-A433342C0D63}.Release|ARM.Build.0 = Debug|Any CPU
- {B0FCE474-14BC-449A-91EA-A433342C0D63}.Release|x64.ActiveCfg = Debug|Any CPU
- {B0FCE474-14BC-449A-91EA-A433342C0D63}.Release|x64.Build.0 = Debug|Any CPU
- {B0FCE474-14BC-449A-91EA-A433342C0D63}.Release|x86.ActiveCfg = Debug|Any CPU
- {B0FCE474-14BC-449A-91EA-A433342C0D63}.Release|x86.Build.0 = Debug|Any CPU
+ {B0FCE474-14BC-449A-91EA-A433342C0D63}.Release|ARM.ActiveCfg = Release|Any CPU
+ {B0FCE474-14BC-449A-91EA-A433342C0D63}.Release|ARM.Build.0 = Release|Any CPU
+ {B0FCE474-14BC-449A-91EA-A433342C0D63}.Release|x64.ActiveCfg = Release|Any CPU
+ {B0FCE474-14BC-449A-91EA-A433342C0D63}.Release|x64.Build.0 = Release|Any CPU
+ {B0FCE474-14BC-449A-91EA-A433342C0D63}.Release|x86.ActiveCfg = Release|Any CPU
+ {B0FCE474-14BC-449A-91EA-A433342C0D63}.Release|x86.Build.0 = Release|Any CPU
{A7EA583B-A2B0-47DA-A058-458F247C7575}.Code Analysis Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A7EA583B-A2B0-47DA-A058-458F247C7575}.Code Analysis Debug|Any CPU.Build.0 = Debug|Any CPU
{A7EA583B-A2B0-47DA-A058-458F247C7575}.Code Analysis Debug|ARM.ActiveCfg = Debug|Any CPU
@@ -1173,6 +1200,30 @@ Global
{E5E58613-82FC-44CD-B75F-4F1C7ED52D0D}.Release|x64.Build.0 = Release|Any CPU
{E5E58613-82FC-44CD-B75F-4F1C7ED52D0D}.Release|x86.ActiveCfg = Release|Any CPU
{E5E58613-82FC-44CD-B75F-4F1C7ED52D0D}.Release|x86.Build.0 = Release|Any CPU
+ {EEE57613-6424-4A1C-9635-B73768F2146D}.Code Analysis Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {EEE57613-6424-4A1C-9635-B73768F2146D}.Code Analysis Debug|Any CPU.Build.0 = Debug|Any CPU
+ {EEE57613-6424-4A1C-9635-B73768F2146D}.Code Analysis Debug|ARM.ActiveCfg = Debug|Any CPU
+ {EEE57613-6424-4A1C-9635-B73768F2146D}.Code Analysis Debug|ARM.Build.0 = Debug|Any CPU
+ {EEE57613-6424-4A1C-9635-B73768F2146D}.Code Analysis Debug|x64.ActiveCfg = Debug|Any CPU
+ {EEE57613-6424-4A1C-9635-B73768F2146D}.Code Analysis Debug|x64.Build.0 = Debug|Any CPU
+ {EEE57613-6424-4A1C-9635-B73768F2146D}.Code Analysis Debug|x86.ActiveCfg = Debug|Any CPU
+ {EEE57613-6424-4A1C-9635-B73768F2146D}.Code Analysis Debug|x86.Build.0 = Debug|Any CPU
+ {EEE57613-6424-4A1C-9635-B73768F2146D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {EEE57613-6424-4A1C-9635-B73768F2146D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {EEE57613-6424-4A1C-9635-B73768F2146D}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {EEE57613-6424-4A1C-9635-B73768F2146D}.Debug|ARM.Build.0 = Debug|Any CPU
+ {EEE57613-6424-4A1C-9635-B73768F2146D}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {EEE57613-6424-4A1C-9635-B73768F2146D}.Debug|x64.Build.0 = Debug|Any CPU
+ {EEE57613-6424-4A1C-9635-B73768F2146D}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {EEE57613-6424-4A1C-9635-B73768F2146D}.Debug|x86.Build.0 = Debug|Any CPU
+ {EEE57613-6424-4A1C-9635-B73768F2146D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {EEE57613-6424-4A1C-9635-B73768F2146D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {EEE57613-6424-4A1C-9635-B73768F2146D}.Release|ARM.ActiveCfg = Release|Any CPU
+ {EEE57613-6424-4A1C-9635-B73768F2146D}.Release|ARM.Build.0 = Release|Any CPU
+ {EEE57613-6424-4A1C-9635-B73768F2146D}.Release|x64.ActiveCfg = Release|Any CPU
+ {EEE57613-6424-4A1C-9635-B73768F2146D}.Release|x64.Build.0 = Release|Any CPU
+ {EEE57613-6424-4A1C-9635-B73768F2146D}.Release|x86.ActiveCfg = Release|Any CPU
+ {EEE57613-6424-4A1C-9635-B73768F2146D}.Release|x86.Build.0 = Release|Any CPU
{23B9D9A2-4AEE-47E6-97B5-060DF21539FB}.Code Analysis Debug|Any CPU.ActiveCfg = Debug|Any CPU
{23B9D9A2-4AEE-47E6-97B5-060DF21539FB}.Code Analysis Debug|Any CPU.Build.0 = Debug|Any CPU
{23B9D9A2-4AEE-47E6-97B5-060DF21539FB}.Code Analysis Debug|ARM.ActiveCfg = Debug|Any CPU
@@ -1197,6 +1248,54 @@ Global
{23B9D9A2-4AEE-47E6-97B5-060DF21539FB}.Release|x64.Build.0 = Release|Any CPU
{23B9D9A2-4AEE-47E6-97B5-060DF21539FB}.Release|x86.ActiveCfg = Release|Any CPU
{23B9D9A2-4AEE-47E6-97B5-060DF21539FB}.Release|x86.Build.0 = Release|Any CPU
+ {F4E2876F-6E42-4DCF-B629-041A9DF7C579}.Code Analysis Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F4E2876F-6E42-4DCF-B629-041A9DF7C579}.Code Analysis Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F4E2876F-6E42-4DCF-B629-041A9DF7C579}.Code Analysis Debug|ARM.ActiveCfg = Debug|ARM
+ {F4E2876F-6E42-4DCF-B629-041A9DF7C579}.Code Analysis Debug|ARM.Build.0 = Debug|ARM
+ {F4E2876F-6E42-4DCF-B629-041A9DF7C579}.Code Analysis Debug|x64.ActiveCfg = Debug|x64
+ {F4E2876F-6E42-4DCF-B629-041A9DF7C579}.Code Analysis Debug|x64.Build.0 = Debug|x64
+ {F4E2876F-6E42-4DCF-B629-041A9DF7C579}.Code Analysis Debug|x86.ActiveCfg = Debug|x86
+ {F4E2876F-6E42-4DCF-B629-041A9DF7C579}.Code Analysis Debug|x86.Build.0 = Debug|x86
+ {F4E2876F-6E42-4DCF-B629-041A9DF7C579}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F4E2876F-6E42-4DCF-B629-041A9DF7C579}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F4E2876F-6E42-4DCF-B629-041A9DF7C579}.Debug|ARM.ActiveCfg = Debug|ARM
+ {F4E2876F-6E42-4DCF-B629-041A9DF7C579}.Debug|ARM.Build.0 = Debug|ARM
+ {F4E2876F-6E42-4DCF-B629-041A9DF7C579}.Debug|x64.ActiveCfg = Debug|x64
+ {F4E2876F-6E42-4DCF-B629-041A9DF7C579}.Debug|x64.Build.0 = Debug|x64
+ {F4E2876F-6E42-4DCF-B629-041A9DF7C579}.Debug|x86.ActiveCfg = Debug|x86
+ {F4E2876F-6E42-4DCF-B629-041A9DF7C579}.Debug|x86.Build.0 = Debug|x86
+ {F4E2876F-6E42-4DCF-B629-041A9DF7C579}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F4E2876F-6E42-4DCF-B629-041A9DF7C579}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F4E2876F-6E42-4DCF-B629-041A9DF7C579}.Release|ARM.ActiveCfg = Release|ARM
+ {F4E2876F-6E42-4DCF-B629-041A9DF7C579}.Release|ARM.Build.0 = Release|ARM
+ {F4E2876F-6E42-4DCF-B629-041A9DF7C579}.Release|x64.ActiveCfg = Release|x64
+ {F4E2876F-6E42-4DCF-B629-041A9DF7C579}.Release|x64.Build.0 = Release|x64
+ {F4E2876F-6E42-4DCF-B629-041A9DF7C579}.Release|x86.ActiveCfg = Release|x86
+ {F4E2876F-6E42-4DCF-B629-041A9DF7C579}.Release|x86.Build.0 = Release|x86
+ {6B4DE65C-4162-4C52-836A-8F9FA901814A}.Code Analysis Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6B4DE65C-4162-4C52-836A-8F9FA901814A}.Code Analysis Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6B4DE65C-4162-4C52-836A-8F9FA901814A}.Code Analysis Debug|ARM.ActiveCfg = Debug|Any CPU
+ {6B4DE65C-4162-4C52-836A-8F9FA901814A}.Code Analysis Debug|ARM.Build.0 = Debug|Any CPU
+ {6B4DE65C-4162-4C52-836A-8F9FA901814A}.Code Analysis Debug|x64.ActiveCfg = Debug|Any CPU
+ {6B4DE65C-4162-4C52-836A-8F9FA901814A}.Code Analysis Debug|x64.Build.0 = Debug|Any CPU
+ {6B4DE65C-4162-4C52-836A-8F9FA901814A}.Code Analysis Debug|x86.ActiveCfg = Debug|Any CPU
+ {6B4DE65C-4162-4C52-836A-8F9FA901814A}.Code Analysis Debug|x86.Build.0 = Debug|Any CPU
+ {6B4DE65C-4162-4C52-836A-8F9FA901814A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6B4DE65C-4162-4C52-836A-8F9FA901814A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6B4DE65C-4162-4C52-836A-8F9FA901814A}.Debug|ARM.ActiveCfg = Debug|Any CPU
+ {6B4DE65C-4162-4C52-836A-8F9FA901814A}.Debug|ARM.Build.0 = Debug|Any CPU
+ {6B4DE65C-4162-4C52-836A-8F9FA901814A}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {6B4DE65C-4162-4C52-836A-8F9FA901814A}.Debug|x64.Build.0 = Debug|Any CPU
+ {6B4DE65C-4162-4C52-836A-8F9FA901814A}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {6B4DE65C-4162-4C52-836A-8F9FA901814A}.Debug|x86.Build.0 = Debug|Any CPU
+ {6B4DE65C-4162-4C52-836A-8F9FA901814A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6B4DE65C-4162-4C52-836A-8F9FA901814A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6B4DE65C-4162-4C52-836A-8F9FA901814A}.Release|ARM.ActiveCfg = Release|Any CPU
+ {6B4DE65C-4162-4C52-836A-8F9FA901814A}.Release|ARM.Build.0 = Release|Any CPU
+ {6B4DE65C-4162-4C52-836A-8F9FA901814A}.Release|x64.ActiveCfg = Release|Any CPU
+ {6B4DE65C-4162-4C52-836A-8F9FA901814A}.Release|x64.Build.0 = Release|Any CPU
+ {6B4DE65C-4162-4C52-836A-8F9FA901814A}.Release|x86.ActiveCfg = Release|Any CPU
+ {6B4DE65C-4162-4C52-836A-8F9FA901814A}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -1261,8 +1360,12 @@ Global
{26F0B8EF-92D4-4A23-ACB4-D1B662F0EEBE} = {D53BD452-F69F-4FB3-8B98-386EDA28A4C8}
{ED27A844-6870-4FE6-8FEF-3ABDD1ED6564} = {D53BD452-F69F-4FB3-8B98-386EDA28A4C8}
{E5E58613-82FC-44CD-B75F-4F1C7ED52D0D} = {D53BD452-F69F-4FB3-8B98-386EDA28A4C8}
+ {EEE57613-6424-4A1C-9635-B73768F2146D} = {F1A27537-78D1-4BBD-8E76-ADB31BC0C2B4}
{23B9D9A2-4AEE-47E6-97B5-060DF21539FB} = {E48AC786-E150-4F41-9A16-32F02E4493D8}
{D11C6664-1C4E-48F0-AA92-7F5BADC6F82C} = {CA01DAF5-8D9D-496E-9AD3-94BB7FBB2D34}
+ {F4E2876F-6E42-4DCF-B629-041A9DF7C579} = {24088844-2107-4DB2-8F3F-CBCA94FC4B28}
+ {35D010CC-CDF2-4115-BCFB-E2E3D21C1055} = {CA01DAF5-8D9D-496E-9AD3-94BB7FBB2D34}
+ {6B4DE65C-4162-4C52-836A-8F9FA901814A} = {D53BD452-F69F-4FB3-8B98-386EDA28A4C8}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {31E0F4D5-975A-41CC-933E-545B2201FAF9}
diff --git a/eng/Tools.props b/eng/Tools.props
new file mode 100644
index 000000000..36a0f1248
--- /dev/null
+++ b/eng/Tools.props
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
new file mode 100644
index 000000000..04eae2ce3
--- /dev/null
+++ b/eng/Version.Details.xml
@@ -0,0 +1,80 @@
+
+
+
+
+ https://dev.azure.com/dnceng/internal/_git/dotnet-symuploader
+ 861806bc0dc685441cb3e8f6bd1ce5ed31e6b32b
+
+
+ https://dev.azure.com/dnceng/internal/_git/dotnet-symuploader
+ 165896e7efeecb70f01bd011257ead0f56d32c95
+
+
+ https://github.com/microsoft/vstest
+ 7603cf3ff7a3b3002362e994b618b828a9250699
+
+
+
+
+ https://github.com/dotnet/arcade
+ e97027cf100d2b532adce387e5cb93a373de93c9
+
+
+ https://github.com/dotnet/arcade
+ e97027cf100d2b532adce387e5cb93a373de93c9
+
+
+ https://github.com/dotnet/arcade
+ e97027cf100d2b532adce387e5cb93a373de93c9
+
+
+ https://github.com/dotnet/arcade
+ e97027cf100d2b532adce387e5cb93a373de93c9
+
+
+ https://github.com/dotnet/arcade
+ e97027cf100d2b532adce387e5cb93a373de93c9
+
+
+ https://github.com/dotnet/arcade-services
+ 869869342f1ec338de96adcea6e003b61f195256
+
+
+ https://github.com/dotnet/arcade-services
+ cac955fe259cb611f6a29d09209bd717deb69037
+
+
+ https://github.com/dotnet/xharness
+ 2eef520188beb49e31460d0a7dbe040294428ff1
+
+
+ https://github.com/dotnet/roslyn
+ 1e347d3e229cf388249d342c72a1222bff0b5fdd
+
+
+ https://github.com/mono/linker
+ 30f2498c2a3de1f7e236d5793f5f1aca6e5ba456
+
+
+ https://github.com/dotnet/sourcelink
+ 4b584dbc392bb1aad49c2eb1ab84d8b489b6dccc
+
+
+
+ https://github.com/dotnet/sourcelink
+ 4b584dbc392bb1aad49c2eb1ab84d8b489b6dccc
+
+
+ https://github.com/dotnet/symreader-converter
+ c5ba7c88f92e2dde156c324a8c8edc04d9fa4fe0
+
+
+ https://github.com/dotnet/symreader-converter
+ c5ba7c88f92e2dde156c324a8c8edc04d9fa4fe0
+
+
+ https://github.com/dotnet/xliff-tasks
+ f4bfde77fb60daf52d8fec738d96d1d54e37dd88
+
+
+
diff --git a/eng/Versions.props b/eng/Versions.props
new file mode 100644
index 000000000..e905dbc99
--- /dev/null
+++ b/eng/Versions.props
@@ -0,0 +1,119 @@
+
+
+
+
+ 6.0.0
+ beta
+
+ false
+ 17.0.0-preview-20210719-01
+
+ 0.2.0
+ 5.9.1
+ 2.5.2
+ 14.0.0
+
+ 1.1.0-beta2-21064-01
+ 1.0.0-build-20170420-1
+ 0.1.3
+ 16.9.0-preview-4267359
+
+
+ 4.3.0
+ 4.3.0
+ 4.3.0
+ 4.3.0
+ 4.3.0
+ 4.3.0
+ 4.3.0
+ 4.3.0
+
+ 1.6.0
+ 1.6.0
+
+ 5.3.0
+ 0.8.0
+
+ 4.8.3
+ 4.3.0
+ 5.10.3
+ 1.0.0
+
+ 15.7.0
+ 1.2.0
+ 1.2.0
+
+ 11.0
+
+ 2.2.1
+ 1.0.2
+ 1.10.1
+ 0.25.2
+ 2.0.10
+ 4.3.4
+ 12.3.0
+ 2.16.0
+ 3.0.0
+ 1.3.1
+ 0.1.0
+ 15.7.179
+ 15.7.179
+ 15.7.179
+ 15.7.179
+ 2.6.3
+ 2.9.0
+ 3.8.0
+ 3.17.2
+ 2.3.13
+ 2.1.0
+ 2.1.1
+ 2.1.1
+ 2.0.0
+ 2.1.1
+ 2.1.0
+ 4.0.0-1.21270.4
+ 6.0.100-preview.5.21268.2
+ 5.3.0.1
+ 2.3.0
+ 9.0.1
+ 4.7.0
+ 4.4.0
+ 5.6.0-preview.2.6489
+ 0.32.0
+ 2.2.143
+ 3.0.0
+ 4.5.0
+ 4.0.0
+ 4.3.0
+ 4.5.0
+ 4.3.0
+ 4.5.3
+ 4.5.0
+ 4.7.0
+ 4.3.0
+ 4.7.2
+ 4.5.2
+ 8.5.0
+ 2.4.1
+ 2.0.3
+ 2.4.1
+ 6.0.0-beta.21369.3
+ 6.0.0-beta.21369.3
+ 1.22.0
+ 1.1.2
+ 2.0.0
+ 1.6.0
+ 1.0.0
+ 2.0.4
+ 1.1.0-beta.20258.6
+ 1.1.0-beta-21228-01
+ 1.1.0-beta-21228-01
+ 6.0.0-beta.21369.3
+ 1.0.0-beta.21265.1
+ 1.1.0-beta.21228.1
+ 1.0.0-prerelease.21264.3
+ 1.1.156402
+ 1.1.152002
+ 6.0.100-preview.5.21254.11
+
+
diff --git a/eng/common/CIBuild.cmd b/eng/common/CIBuild.cmd
new file mode 100644
index 000000000..56c2f25ac
--- /dev/null
+++ b/eng/common/CIBuild.cmd
@@ -0,0 +1,2 @@
+@echo off
+powershell -ExecutionPolicy ByPass -NoProfile -command "& """%~dp0Build.ps1""" -restore -build -test -sign -pack -publish -ci %*"
\ No newline at end of file
diff --git a/eng/common/PSScriptAnalyzerSettings.psd1 b/eng/common/PSScriptAnalyzerSettings.psd1
new file mode 100644
index 000000000..4c1ea7c98
--- /dev/null
+++ b/eng/common/PSScriptAnalyzerSettings.psd1
@@ -0,0 +1,11 @@
+@{
+ IncludeRules=@('PSAvoidUsingCmdletAliases',
+ 'PSAvoidUsingWMICmdlet',
+ 'PSAvoidUsingPositionalParameters',
+ 'PSAvoidUsingInvokeExpression',
+ 'PSUseDeclaredVarsMoreThanAssignments',
+ 'PSUseCmdletCorrectly',
+ 'PSStandardDSCFunctionsInResource',
+ 'PSUseIdenticalMandatoryParametersForDSC',
+ 'PSUseIdenticalParametersForDSC')
+}
\ No newline at end of file
diff --git a/eng/common/README.md b/eng/common/README.md
new file mode 100644
index 000000000..ff49c3715
--- /dev/null
+++ b/eng/common/README.md
@@ -0,0 +1,28 @@
+# Don't touch this folder
+
+ uuuuuuuuuuuuuuuuuuuu
+ u" uuuuuuuuuuuuuuuuuu "u
+ u" u$$$$$$$$$$$$$$$$$$$$u "u
+ u" u$$$$$$$$$$$$$$$$$$$$$$$$u "u
+ u" u$$$$$$$$$$$$$$$$$$$$$$$$$$$$u "u
+ u" u$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$u "u
+ u" u$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$u "u
+ $ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $
+ $ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $
+ $ $$$" ... "$... ...$" ... "$$$ ... "$$$ $
+ $ $$$u `"$$$$$$$ $$$ $$$$$ $$ $$$ $$$ $
+ $ $$$$$$uu "$$$$ $$$ $$$$$ $$ """ u$$$ $
+ $ $$$""$$$ $$$$ $$$u "$$$" u$$ $$$$$$$$ $
+ $ $$$$....,$$$$$..$$$$$....,$$$$..$$$$$$$$ $
+ $ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $
+ "u "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" u"
+ "u "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" u"
+ "u "$$$$$$$$$$$$$$$$$$$$$$$$$$$$" u"
+ "u "$$$$$$$$$$$$$$$$$$$$$$$$" u"
+ "u "$$$$$$$$$$$$$$$$$$$$" u"
+ "u """""""""""""""""" u"
+ """"""""""""""""""""
+
+!!! Changes made in this directory are subject to being overwritten by automation !!!
+
+The files in this directory are shared by all Arcade repos and managed by automation. If you need to make changes to these files, open an issue or submit a pull request to https://github.com/dotnet/arcade first.
diff --git a/eng/common/SetupNugetSources.ps1 b/eng/common/SetupNugetSources.ps1
new file mode 100644
index 000000000..18823840b
--- /dev/null
+++ b/eng/common/SetupNugetSources.ps1
@@ -0,0 +1,167 @@
+# This file is a temporary workaround for internal builds to be able to restore from private AzDO feeds.
+# This file should be removed as part of this issue: https://github.com/dotnet/arcade/issues/4080
+#
+# What the script does is iterate over all package sources in the pointed NuGet.config and add a credential entry
+# under for each Maestro managed private feed. Two additional credential
+# entries are also added for the two private static internal feeds: dotnet3-internal and dotnet3-internal-transport.
+#
+# This script needs to be called in every job that will restore packages and which the base repo has
+# private AzDO feeds in the NuGet.config.
+#
+# See example YAML call for this script below. Note the use of the variable `$(dn-bot-dnceng-artifact-feeds-rw)`
+# from the AzureDevOps-Artifact-Feeds-Pats variable group.
+#
+# Any disabledPackageSources entries which start with "darc-int" will be re-enabled as part of this script executing
+#
+# - task: PowerShell@2
+# displayName: Setup Private Feeds Credentials
+# condition: eq(variables['Agent.OS'], 'Windows_NT')
+# inputs:
+# filePath: $(Build.SourcesDirectory)/eng/common/SetupNugetSources.ps1
+# arguments: -ConfigFile $(Build.SourcesDirectory)/NuGet.config -Password $Env:Token
+# env:
+# Token: $(dn-bot-dnceng-artifact-feeds-rw)
+
+[CmdletBinding()]
+param (
+ [Parameter(Mandatory = $true)][string]$ConfigFile,
+ [Parameter(Mandatory = $true)][string]$Password
+)
+
+$ErrorActionPreference = "Stop"
+Set-StrictMode -Version 2.0
+[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
+
+. $PSScriptRoot\tools.ps1
+
+# Add source entry to PackageSources
+function AddPackageSource($sources, $SourceName, $SourceEndPoint, $creds, $Username, $Password) {
+ $packageSource = $sources.SelectSingleNode("add[@key='$SourceName']")
+
+ if ($packageSource -eq $null)
+ {
+ $packageSource = $doc.CreateElement("add")
+ $packageSource.SetAttribute("key", $SourceName)
+ $packageSource.SetAttribute("value", $SourceEndPoint)
+ $sources.AppendChild($packageSource) | Out-Null
+ }
+ else {
+ Write-Host "Package source $SourceName already present."
+ }
+
+ AddCredential -Creds $creds -Source $SourceName -Username $Username -Password $Password
+}
+
+# Add a credential node for the specified source
+function AddCredential($creds, $source, $username, $password) {
+ # Looks for credential configuration for the given SourceName. Create it if none is found.
+ $sourceElement = $creds.SelectSingleNode($Source)
+ if ($sourceElement -eq $null)
+ {
+ $sourceElement = $doc.CreateElement($Source)
+ $creds.AppendChild($sourceElement) | Out-Null
+ }
+
+ # Add the node to the credential if none is found.
+ $usernameElement = $sourceElement.SelectSingleNode("add[@key='Username']")
+ if ($usernameElement -eq $null)
+ {
+ $usernameElement = $doc.CreateElement("add")
+ $usernameElement.SetAttribute("key", "Username")
+ $sourceElement.AppendChild($usernameElement) | Out-Null
+ }
+ $usernameElement.SetAttribute("value", $Username)
+
+ # Add the to the credential if none is found.
+ # Add it as a clear text because there is no support for encrypted ones in non-windows .Net SDKs.
+ # -> https://github.com/NuGet/Home/issues/5526
+ $passwordElement = $sourceElement.SelectSingleNode("add[@key='ClearTextPassword']")
+ if ($passwordElement -eq $null)
+ {
+ $passwordElement = $doc.CreateElement("add")
+ $passwordElement.SetAttribute("key", "ClearTextPassword")
+ $sourceElement.AppendChild($passwordElement) | Out-Null
+ }
+ $passwordElement.SetAttribute("value", $Password)
+}
+
+function InsertMaestroPrivateFeedCredentials($Sources, $Creds, $Username, $Password) {
+ $maestroPrivateSources = $Sources.SelectNodes("add[contains(@key,'darc-int')]")
+
+ Write-Host "Inserting credentials for $($maestroPrivateSources.Count) Maestro's private feeds."
+
+ ForEach ($PackageSource in $maestroPrivateSources) {
+ Write-Host "`tInserting credential for Maestro's feed:" $PackageSource.Key
+ AddCredential -Creds $creds -Source $PackageSource.Key -Username $Username -Password $Password
+ }
+}
+
+function EnablePrivatePackageSources($DisabledPackageSources) {
+ $maestroPrivateSources = $DisabledPackageSources.SelectNodes("add[contains(@key,'darc-int')]")
+ ForEach ($DisabledPackageSource in $maestroPrivateSources) {
+ Write-Host "`tEnsuring private source '$($DisabledPackageSource.key)' is enabled by deleting it from disabledPackageSource"
+ # Due to https://github.com/NuGet/Home/issues/10291, we must actually remove the disabled entries
+ $DisabledPackageSources.RemoveChild($DisabledPackageSource)
+ }
+}
+
+if (!(Test-Path $ConfigFile -PathType Leaf)) {
+ Write-PipelineTelemetryError -Category 'Build' -Message "Eng/common/SetupNugetSources.ps1 returned a non-zero exit code. Couldn't find the NuGet config file: $ConfigFile"
+ ExitWithExitCode 1
+}
+
+if (!$Password) {
+ Write-PipelineTelemetryError -Category 'Build' -Message 'Eng/common/SetupNugetSources.ps1 returned a non-zero exit code. Please supply a valid PAT'
+ ExitWithExitCode 1
+}
+
+# Load NuGet.config
+$doc = New-Object System.Xml.XmlDocument
+$filename = (Get-Item $ConfigFile).FullName
+$doc.Load($filename)
+
+# Get reference to or create one if none exist already
+$sources = $doc.DocumentElement.SelectSingleNode("packageSources")
+if ($sources -eq $null) {
+ $sources = $doc.CreateElement("packageSources")
+ $doc.DocumentElement.AppendChild($sources) | Out-Null
+}
+
+# Looks for a node. Create it if none is found.
+$creds = $doc.DocumentElement.SelectSingleNode("packageSourceCredentials")
+if ($creds -eq $null) {
+ $creds = $doc.CreateElement("packageSourceCredentials")
+ $doc.DocumentElement.AppendChild($creds) | Out-Null
+}
+
+# Check for disabledPackageSources; we'll enable any darc-int ones we find there
+$disabledSources = $doc.DocumentElement.SelectSingleNode("disabledPackageSources")
+if ($disabledSources -ne $null) {
+ Write-Host "Checking for any darc-int disabled package sources in the disabledPackageSources node"
+ EnablePrivatePackageSources -DisabledPackageSources $disabledSources
+}
+
+$userName = "dn-bot"
+
+# Insert credential nodes for Maestro's private feeds
+InsertMaestroPrivateFeedCredentials -Sources $sources -Creds $creds -Username $userName -Password $Password
+
+$dotnet31Source = $sources.SelectSingleNode("add[@key='dotnet3.1']")
+if ($dotnet31Source -ne $null) {
+ AddPackageSource -Sources $sources -SourceName "dotnet3.1-internal" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal/nuget/v2" -Creds $creds -Username $userName -Password $Password
+ AddPackageSource -Sources $sources -SourceName "dotnet3.1-internal-transport" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal-transport/nuget/v2" -Creds $creds -Username $userName -Password $Password
+}
+
+$dotnet5Source = $sources.SelectSingleNode("add[@key='dotnet5']")
+if ($dotnet5Source -ne $null) {
+ AddPackageSource -Sources $sources -SourceName "dotnet5-internal" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet5-internal/nuget/v2" -Creds $creds -Username $userName -Password $Password
+ AddPackageSource -Sources $sources -SourceName "dotnet5-internal-transport" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet5-internal-transport/nuget/v2" -Creds $creds -Username $userName -Password $Password
+}
+
+$dotnet6Source = $sources.SelectSingleNode("add[@key='dotnet6']")
+if ($dotnet6Source -ne $null) {
+ AddPackageSource -Sources $sources -SourceName "dotnet6-internal" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet6-internal/nuget/v2" -Creds $creds -Username $userName -Password $Password
+ AddPackageSource -Sources $sources -SourceName "dotnet6-internal-transport" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet6-internal-transport/nuget/v2" -Creds $creds -Username $userName -Password $Password
+}
+
+$doc.Save($filename)
diff --git a/eng/common/SetupNugetSources.sh b/eng/common/SetupNugetSources.sh
new file mode 100644
index 000000000..ad3fb74fd
--- /dev/null
+++ b/eng/common/SetupNugetSources.sh
@@ -0,0 +1,191 @@
+#!/usr/bin/env bash
+
+# This file is a temporary workaround for internal builds to be able to restore from private AzDO feeds.
+# This file should be removed as part of this issue: https://github.com/dotnet/arcade/issues/4080
+#
+# What the script does is iterate over all package sources in the pointed NuGet.config and add a credential entry
+# under for each Maestro's managed private feed. Two additional credential
+# entries are also added for the two private static internal feeds: dotnet3-internal and dotnet3-internal-transport.
+#
+# This script needs to be called in every job that will restore packages and which the base repo has
+# private AzDO feeds in the NuGet.config.
+#
+# See example YAML call for this script below. Note the use of the variable `$(dn-bot-dnceng-artifact-feeds-rw)`
+# from the AzureDevOps-Artifact-Feeds-Pats variable group.
+#
+# Any disabledPackageSources entries which start with "darc-int" will be re-enabled as part of this script executing.
+#
+# - task: Bash@3
+# displayName: Setup Private Feeds Credentials
+# inputs:
+# filePath: $(Build.SourcesDirectory)/eng/common/SetupNugetSources.sh
+# arguments: $(Build.SourcesDirectory)/NuGet.config $Token
+# condition: ne(variables['Agent.OS'], 'Windows_NT')
+# env:
+# Token: $(dn-bot-dnceng-artifact-feeds-rw)
+
+ConfigFile=$1
+CredToken=$2
+NL='\n'
+TB=' '
+
+source="${BASH_SOURCE[0]}"
+
+# resolve $source until the file is no longer a symlink
+while [[ -h "$source" ]]; do
+ scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+ source="$(readlink "$source")"
+ # if $source was a relative symlink, we need to resolve it relative to the path where the
+ # symlink file was located
+ [[ $source != /* ]] && source="$scriptroot/$source"
+done
+scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+
+. "$scriptroot/tools.sh"
+
+if [ ! -f "$ConfigFile" ]; then
+ Write-PipelineTelemetryError -Category 'Build' "Error: Eng/common/SetupNugetSources.sh returned a non-zero exit code. Couldn't find the NuGet config file: $ConfigFile"
+ ExitWithExitCode 1
+fi
+
+if [ -z "$CredToken" ]; then
+ Write-PipelineTelemetryError -category 'Build' "Error: Eng/common/SetupNugetSources.sh returned a non-zero exit code. Please supply a valid PAT"
+ ExitWithExitCode 1
+fi
+
+if [[ `uname -s` == "Darwin" ]]; then
+ NL=$'\\\n'
+ TB=''
+fi
+
+# Ensure there is a ... section.
+grep -i "" $ConfigFile
+if [ "$?" != "0" ]; then
+ echo "Adding ... section."
+ ConfigNodeHeader=""
+ PackageSourcesTemplate="${TB}${NL}${TB}"
+
+ sed -i.bak "s|$ConfigNodeHeader|$ConfigNodeHeader${NL}$PackageSourcesTemplate|" $ConfigFile
+fi
+
+# Ensure there is a ... section.
+grep -i "" $ConfigFile
+if [ "$?" != "0" ]; then
+ echo "Adding ... section."
+
+ PackageSourcesNodeFooter=""
+ PackageSourceCredentialsTemplate="${TB}${NL}${TB}"
+
+ sed -i.bak "s|$PackageSourcesNodeFooter|$PackageSourcesNodeFooter${NL}$PackageSourceCredentialsTemplate|" $ConfigFile
+fi
+
+PackageSources=()
+
+# Ensure dotnet3.1-internal and dotnet3.1-internal-transport are in the packageSources if the public dotnet3.1 feeds are present
+grep -i ""
+
+ sed -i.bak "s|$PackageSourcesNodeFooter|$PackageSourceTemplate${NL}$PackageSourcesNodeFooter|" $ConfigFile
+ fi
+ PackageSources+=('dotnet3.1-internal')
+
+ grep -i "" $ConfigFile
+ if [ "$?" != "0" ]; then
+ echo "Adding dotnet3.1-internal-transport to the packageSources."
+ PackageSourcesNodeFooter=""
+ PackageSourceTemplate="${TB}"
+
+ sed -i.bak "s|$PackageSourcesNodeFooter|$PackageSourceTemplate${NL}$PackageSourcesNodeFooter|" $ConfigFile
+ fi
+ PackageSources+=('dotnet3.1-internal-transport')
+fi
+
+# Ensure dotnet5-internal and dotnet5-internal-transport are in the packageSources if the public dotnet5 feeds are present
+grep -i ""
+
+ sed -i.bak "s|$PackageSourcesNodeFooter|$PackageSourceTemplate${NL}$PackageSourcesNodeFooter|" $ConfigFile
+ fi
+ PackageSources+=('dotnet5-internal')
+
+ grep -i "" $ConfigFile
+ if [ "$?" != "0" ]; then
+ echo "Adding dotnet5-internal-transport to the packageSources."
+ PackageSourcesNodeFooter=""
+ PackageSourceTemplate="${TB}"
+
+ sed -i.bak "s|$PackageSourcesNodeFooter|$PackageSourceTemplate${NL}$PackageSourcesNodeFooter|" $ConfigFile
+ fi
+ PackageSources+=('dotnet5-internal-transport')
+fi
+
+# Ensure dotnet6-internal and dotnet6-internal-transport are in the packageSources if the public dotnet6 feeds are present
+grep -i ""
+
+ sed -i.bak "s|$PackageSourcesNodeFooter|$PackageSourceTemplate${NL}$PackageSourcesNodeFooter|" $ConfigFile
+ fi
+ PackageSources+=('dotnet6-internal')
+
+ grep -i "" $ConfigFile
+ if [ "$?" != "0" ]; then
+ echo "Adding dotnet6-internal-transport to the packageSources."
+ PackageSourcesNodeFooter=""
+ PackageSourceTemplate="${TB}"
+
+ sed -i.bak "s|$PackageSourcesNodeFooter|$PackageSourceTemplate${NL}$PackageSourcesNodeFooter|" $ConfigFile
+ fi
+ PackageSources+=('dotnet6-internal-transport')
+fi
+
+# I want things split line by line
+PrevIFS=$IFS
+IFS=$'\n'
+PackageSources+="$IFS"
+PackageSources+=$(grep -oh '"darc-int-[^"]*"' $ConfigFile | tr -d '"')
+IFS=$PrevIFS
+
+for FeedName in ${PackageSources[@]} ; do
+ # Check if there is no existing credential for this FeedName
+ grep -i "<$FeedName>" $ConfigFile
+ if [ "$?" != "0" ]; then
+ echo "Adding credentials for $FeedName."
+
+ PackageSourceCredentialsNodeFooter=""
+ NewCredential="${TB}${TB}<$FeedName>${NL}${NL}${NL}$FeedName>"
+
+ sed -i.bak "s|$PackageSourceCredentialsNodeFooter|$NewCredential${NL}$PackageSourceCredentialsNodeFooter|" $ConfigFile
+ fi
+done
+
+# Re-enable any entries in disabledPackageSources where the feed name contains darc-int
+grep -i "" $ConfigFile
+if [ "$?" == "0" ]; then
+ DisabledDarcIntSources=()
+ echo "Re-enabling any disabled \"darc-int\" package sources in $ConfigFile"
+ DisabledDarcIntSources+=$(grep -oh '"darc-int-[^"]*" value="true"' $ConfigFile | tr -d '"')
+ for DisabledSourceName in ${DisabledDarcIntSources[@]} ; do
+ if [[ $DisabledSourceName == darc-int* ]]
+ then
+ OldDisableValue=""
+ NewDisableValue=""
+ sed -i.bak "s|$OldDisableValue|$NewDisableValue|" $ConfigFile
+ echo "Neutralized disablePackageSources entry for '$DisabledSourceName'"
+ fi
+ done
+fi
diff --git a/eng/common/build.ps1 b/eng/common/build.ps1
new file mode 100644
index 000000000..8943da242
--- /dev/null
+++ b/eng/common/build.ps1
@@ -0,0 +1,161 @@
+[CmdletBinding(PositionalBinding=$false)]
+Param(
+ [string][Alias('c')]$configuration = "Debug",
+ [string]$platform = $null,
+ [string] $projects,
+ [string][Alias('v')]$verbosity = "minimal",
+ [string] $msbuildEngine = $null,
+ [bool] $warnAsError = $true,
+ [bool] $nodeReuse = $true,
+ [switch][Alias('r')]$restore,
+ [switch] $deployDeps,
+ [switch][Alias('b')]$build,
+ [switch] $rebuild,
+ [switch] $deploy,
+ [switch][Alias('t')]$test,
+ [switch] $integrationTest,
+ [switch] $performanceTest,
+ [switch] $sign,
+ [switch] $pack,
+ [switch] $publish,
+ [switch] $clean,
+ [switch][Alias('bl')]$binaryLog,
+ [switch][Alias('nobl')]$excludeCIBinarylog,
+ [switch] $ci,
+ [switch] $prepareMachine,
+ [string] $runtimeSourceFeed = '',
+ [string] $runtimeSourceFeedKey = '',
+ [switch] $excludePrereleaseVS,
+ [switch] $help,
+ [Parameter(ValueFromRemainingArguments=$true)][String[]]$properties
+)
+
+# Unset 'Platform' environment variable to avoid unwanted collision in InstallDotNetCore.targets file
+# some computer has this env var defined (e.g. Some HP)
+if($env:Platform) {
+ $env:Platform=""
+}
+function Print-Usage() {
+ Write-Host "Common settings:"
+ Write-Host " -configuration Build configuration: 'Debug' or 'Release' (short: -c)"
+ Write-Host " -platform Platform configuration: 'x86', 'x64' or any valid Platform value to pass to msbuild"
+ Write-Host " -verbosity Msbuild verbosity: q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic] (short: -v)"
+ Write-Host " -binaryLog Output binary log (short: -bl)"
+ Write-Host " -help Print help and exit"
+ Write-Host ""
+
+ Write-Host "Actions:"
+ Write-Host " -restore Restore dependencies (short: -r)"
+ Write-Host " -build Build solution (short: -b)"
+ Write-Host " -rebuild Rebuild solution"
+ Write-Host " -deploy Deploy built VSIXes"
+ Write-Host " -deployDeps Deploy dependencies (e.g. VSIXes for integration tests)"
+ Write-Host " -test Run all unit tests in the solution (short: -t)"
+ Write-Host " -integrationTest Run all integration tests in the solution"
+ Write-Host " -performanceTest Run all performance tests in the solution"
+ Write-Host " -pack Package build outputs into NuGet packages and Willow components"
+ Write-Host " -sign Sign build outputs"
+ Write-Host " -publish Publish artifacts (e.g. symbols)"
+ Write-Host " -clean Clean the solution"
+ Write-Host ""
+
+ Write-Host "Advanced settings:"
+ Write-Host " -projects Semi-colon delimited list of sln/proj's to build. Globbing is supported (*.sln)"
+ Write-Host " -ci Set when running on CI server"
+ Write-Host " -excludeCIBinarylog Don't output binary log (short: -nobl)"
+ Write-Host " -prepareMachine Prepare machine for CI run, clean up processes after build"
+ Write-Host " -warnAsError Sets warnaserror msbuild parameter ('true' or 'false')"
+ Write-Host " -msbuildEngine Msbuild engine to use to run build ('dotnet', 'vs', or unspecified)."
+ Write-Host " -excludePrereleaseVS Set to exclude build engines in prerelease versions of Visual Studio"
+ Write-Host ""
+
+ Write-Host "Command line arguments not listed above are passed thru to msbuild."
+ Write-Host "The above arguments can be shortened as much as to be unambiguous (e.g. -co for configuration, -t for test, etc.)."
+}
+
+. $PSScriptRoot\tools.ps1
+
+function InitializeCustomToolset {
+ if (-not $restore) {
+ return
+ }
+
+ $script = Join-Path $EngRoot 'restore-toolset.ps1'
+
+ if (Test-Path $script) {
+ . $script
+ }
+}
+
+function Build {
+ $toolsetBuildProj = InitializeToolset
+ InitializeCustomToolset
+
+ $bl = if ($binaryLog) { '/bl:' + (Join-Path $LogDir 'Build.binlog') } else { '' }
+ $platformArg = if ($platform) { "/p:Platform=$platform" } else { '' }
+
+ if ($projects) {
+ # Re-assign properties to a new variable because PowerShell doesn't let us append properties directly for unclear reasons.
+ # Explicitly set the type as string[] because otherwise PowerShell would make this char[] if $properties is empty.
+ [string[]] $msbuildArgs = $properties
+
+ # Resolve relative project paths into full paths
+ $projects = ($projects.Split(';').ForEach({Resolve-Path $_}) -join ';')
+
+ $msbuildArgs += "/p:Projects=$projects"
+ $properties = $msbuildArgs
+ }
+
+ MSBuild $toolsetBuildProj `
+ $bl `
+ $platformArg `
+ /p:Configuration=$configuration `
+ /p:RepoRoot=$RepoRoot `
+ /p:Restore=$restore `
+ /p:DeployDeps=$deployDeps `
+ /p:Build=$build `
+ /p:Rebuild=$rebuild `
+ /p:Deploy=$deploy `
+ /p:Test=$test `
+ /p:Pack=$pack `
+ /p:IntegrationTest=$integrationTest `
+ /p:PerformanceTest=$performanceTest `
+ /p:Sign=$sign `
+ /p:Publish=$publish `
+ @properties
+}
+
+try {
+ if ($clean) {
+ if (Test-Path $ArtifactsDir) {
+ Remove-Item -Recurse -Force $ArtifactsDir
+ Write-Host 'Artifacts directory deleted.'
+ }
+ exit 0
+ }
+
+ if ($help -or (($null -ne $properties) -and ($properties.Contains('/help') -or $properties.Contains('/?')))) {
+ Print-Usage
+ exit 0
+ }
+
+ if ($ci) {
+ if (-not $excludeCIBinarylog) {
+ $binaryLog = $true
+ }
+ $nodeReuse = $false
+ }
+
+ if ($restore) {
+ InitializeNativeTools
+ }
+
+ Build
+}
+catch {
+ Write-Host $_.ScriptStackTrace
+ Write-PipelineTelemetryError -Category 'InitializeToolset' -Message $_
+ ExitWithExitCode 1
+}
+
+ExitWithExitCode 0
diff --git a/eng/common/build.sh b/eng/common/build.sh
new file mode 100644
index 000000000..55b298f16
--- /dev/null
+++ b/eng/common/build.sh
@@ -0,0 +1,232 @@
+#!/usr/bin/env bash
+
+# Stop script if unbound variable found (use ${var:-} if intentional)
+set -u
+
+# Stop script if command returns non-zero exit code.
+# Prevents hidden errors caused by missing error code propagation.
+set -e
+
+usage()
+{
+ echo "Common settings:"
+ echo " --configuration Build configuration: 'Debug' or 'Release' (short: -c)"
+ echo " --verbosity Msbuild verbosity: q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic] (short: -v)"
+ echo " --binaryLog Create MSBuild binary log (short: -bl)"
+ echo " --help Print help and exit (short: -h)"
+ echo ""
+
+ echo "Actions:"
+ echo " --restore Restore dependencies (short: -r)"
+ echo " --build Build solution (short: -b)"
+ echo " --rebuild Rebuild solution"
+ echo " --test Run all unit tests in the solution (short: -t)"
+ echo " --integrationTest Run all integration tests in the solution"
+ echo " --performanceTest Run all performance tests in the solution"
+ echo " --pack Package build outputs into NuGet packages and Willow components"
+ echo " --sign Sign build outputs"
+ echo " --publish Publish artifacts (e.g. symbols)"
+ echo " --clean Clean the solution"
+ echo ""
+
+ echo "Advanced settings:"
+ echo " --projects Project or solution file(s) to build"
+ echo " --ci Set when running on CI server"
+ echo " --excludeCIBinarylog Don't output binary log (short: -nobl)"
+ echo " --prepareMachine Prepare machine for CI run, clean up processes after build"
+ echo " --nodeReuse Sets nodereuse msbuild parameter ('true' or 'false')"
+ echo " --warnAsError Sets warnaserror msbuild parameter ('true' or 'false')"
+ echo ""
+ echo "Command line arguments not listed above are passed thru to msbuild."
+ echo "Arguments can also be passed in with a single hyphen."
+}
+
+source="${BASH_SOURCE[0]}"
+
+# resolve $source until the file is no longer a symlink
+while [[ -h "$source" ]]; do
+ scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+ source="$(readlink "$source")"
+ # if $source was a relative symlink, we need to resolve it relative to the path where the
+ # symlink file was located
+ [[ $source != /* ]] && source="$scriptroot/$source"
+done
+scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+
+restore=false
+build=false
+rebuild=false
+test=false
+integration_test=false
+performance_test=false
+pack=false
+publish=false
+sign=false
+public=false
+ci=false
+clean=false
+
+warn_as_error=true
+node_reuse=true
+binary_log=false
+exclude_ci_binary_log=false
+pipelines_log=false
+
+projects=''
+configuration='Debug'
+prepare_machine=false
+verbosity='minimal'
+runtime_source_feed=''
+runtime_source_feed_key=''
+
+properties=''
+while [[ $# > 0 ]]; do
+ opt="$(echo "${1/#--/-}" | tr "[:upper:]" "[:lower:]")"
+ case "$opt" in
+ -help|-h)
+ usage
+ exit 0
+ ;;
+ -clean)
+ clean=true
+ ;;
+ -configuration|-c)
+ configuration=$2
+ shift
+ ;;
+ -verbosity|-v)
+ verbosity=$2
+ shift
+ ;;
+ -binarylog|-bl)
+ binary_log=true
+ ;;
+ -excludeCIBinarylog|-nobl)
+ exclude_ci_binary_log=true
+ ;;
+ -pipelineslog|-pl)
+ pipelines_log=true
+ ;;
+ -restore|-r)
+ restore=true
+ ;;
+ -build|-b)
+ build=true
+ ;;
+ -rebuild)
+ rebuild=true
+ ;;
+ -pack)
+ pack=true
+ ;;
+ -test|-t)
+ test=true
+ ;;
+ -integrationtest)
+ integration_test=true
+ ;;
+ -performancetest)
+ performance_test=true
+ ;;
+ -sign)
+ sign=true
+ ;;
+ -publish)
+ publish=true
+ ;;
+ -preparemachine)
+ prepare_machine=true
+ ;;
+ -projects)
+ projects=$2
+ shift
+ ;;
+ -ci)
+ ci=true
+ ;;
+ -warnaserror)
+ warn_as_error=$2
+ shift
+ ;;
+ -nodereuse)
+ node_reuse=$2
+ shift
+ ;;
+ -runtimesourcefeed)
+ runtime_source_feed=$2
+ shift
+ ;;
+ -runtimesourcefeedkey)
+ runtime_source_feed_key=$2
+ shift
+ ;;
+ *)
+ properties="$properties $1"
+ ;;
+ esac
+
+ shift
+done
+
+if [[ "$ci" == true ]]; then
+ pipelines_log=true
+ node_reuse=false
+ if [[ "$exclude_ci_binary_log" == false ]]; then
+ binary_log=true
+ fi
+fi
+
+. "$scriptroot/tools.sh"
+
+function InitializeCustomToolset {
+ local script="$eng_root/restore-toolset.sh"
+
+ if [[ -a "$script" ]]; then
+ . "$script"
+ fi
+}
+
+function Build {
+ InitializeToolset
+ InitializeCustomToolset
+
+ if [[ ! -z "$projects" ]]; then
+ properties="$properties /p:Projects=$projects"
+ fi
+
+ local bl=""
+ if [[ "$binary_log" == true ]]; then
+ bl="/bl:\"$log_dir/Build.binlog\""
+ fi
+
+ MSBuild $_InitializeToolset \
+ $bl \
+ /p:Configuration=$configuration \
+ /p:RepoRoot="$repo_root" \
+ /p:Restore=$restore \
+ /p:Build=$build \
+ /p:Rebuild=$rebuild \
+ /p:Test=$test \
+ /p:Pack=$pack \
+ /p:IntegrationTest=$integration_test \
+ /p:PerformanceTest=$performance_test \
+ /p:Sign=$sign \
+ /p:Publish=$publish \
+ $properties
+
+ ExitWithExitCode 0
+}
+
+if [[ "$clean" == true ]]; then
+ if [ -d "$artifacts_dir" ]; then
+ rm -rf $artifacts_dir
+ echo "Artifacts directory deleted."
+ fi
+ exit 0
+fi
+
+if [[ "$restore" == true ]]; then
+ InitializeNativeTools
+fi
+
+Build
diff --git a/eng/common/cibuild.sh b/eng/common/cibuild.sh
new file mode 100644
index 000000000..1a02c0dec
--- /dev/null
+++ b/eng/common/cibuild.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+
+source="${BASH_SOURCE[0]}"
+
+# resolve $SOURCE until the file is no longer a symlink
+while [[ -h $source ]]; do
+ scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+ source="$(readlink "$source")"
+
+ # if $source was a relative symlink, we need to resolve it relative to the path where
+ # the symlink file was located
+ [[ $source != /* ]] && source="$scriptroot/$source"
+done
+scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+
+. "$scriptroot/build.sh" --restore --build --test --pack --publish --ci $@
\ No newline at end of file
diff --git a/eng/common/cross/arm/sources.list.bionic b/eng/common/cross/arm/sources.list.bionic
new file mode 100644
index 000000000..210955740
--- /dev/null
+++ b/eng/common/cross/arm/sources.list.bionic
@@ -0,0 +1,11 @@
+deb http://ports.ubuntu.com/ubuntu-ports/ bionic main restricted universe
+deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic main restricted universe
+
+deb http://ports.ubuntu.com/ubuntu-ports/ bionic-updates main restricted universe
+deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic-updates main restricted universe
+
+deb http://ports.ubuntu.com/ubuntu-ports/ bionic-backports main restricted
+deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic-backports main restricted
+
+deb http://ports.ubuntu.com/ubuntu-ports/ bionic-security main restricted universe multiverse
+deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic-security main restricted universe multiverse
diff --git a/eng/common/cross/arm/sources.list.jessie b/eng/common/cross/arm/sources.list.jessie
new file mode 100644
index 000000000..4d142ac9b
--- /dev/null
+++ b/eng/common/cross/arm/sources.list.jessie
@@ -0,0 +1,3 @@
+# Debian (sid) # UNSTABLE
+deb http://ftp.debian.org/debian/ sid main contrib non-free
+deb-src http://ftp.debian.org/debian/ sid main contrib non-free
diff --git a/eng/common/cross/arm/sources.list.trusty b/eng/common/cross/arm/sources.list.trusty
new file mode 100644
index 000000000..07d8f88d8
--- /dev/null
+++ b/eng/common/cross/arm/sources.list.trusty
@@ -0,0 +1,11 @@
+deb http://ports.ubuntu.com/ubuntu-ports/ trusty main restricted universe
+deb-src http://ports.ubuntu.com/ubuntu-ports/ trusty main restricted universe
+
+deb http://ports.ubuntu.com/ubuntu-ports/ trusty-updates main restricted universe
+deb-src http://ports.ubuntu.com/ubuntu-ports/ trusty-updates main restricted universe
+
+deb http://ports.ubuntu.com/ubuntu-ports/ trusty-backports main restricted
+deb-src http://ports.ubuntu.com/ubuntu-ports/ trusty-backports main restricted
+
+deb http://ports.ubuntu.com/ubuntu-ports/ trusty-security main restricted universe multiverse
+deb-src http://ports.ubuntu.com/ubuntu-ports/ trusty-security main restricted universe multiverse
\ No newline at end of file
diff --git a/eng/common/cross/arm/sources.list.xenial b/eng/common/cross/arm/sources.list.xenial
new file mode 100644
index 000000000..eacd86b7d
--- /dev/null
+++ b/eng/common/cross/arm/sources.list.xenial
@@ -0,0 +1,11 @@
+deb http://ports.ubuntu.com/ubuntu-ports/ xenial main restricted universe
+deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial main restricted universe
+
+deb http://ports.ubuntu.com/ubuntu-ports/ xenial-updates main restricted universe
+deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial-updates main restricted universe
+
+deb http://ports.ubuntu.com/ubuntu-ports/ xenial-backports main restricted
+deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial-backports main restricted
+
+deb http://ports.ubuntu.com/ubuntu-ports/ xenial-security main restricted universe multiverse
+deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial-security main restricted universe multiverse
\ No newline at end of file
diff --git a/eng/common/cross/arm/sources.list.zesty b/eng/common/cross/arm/sources.list.zesty
new file mode 100644
index 000000000..ea2c14a78
--- /dev/null
+++ b/eng/common/cross/arm/sources.list.zesty
@@ -0,0 +1,11 @@
+deb http://ports.ubuntu.com/ubuntu-ports/ zesty main restricted universe
+deb-src http://ports.ubuntu.com/ubuntu-ports/ zesty main restricted universe
+
+deb http://ports.ubuntu.com/ubuntu-ports/ zesty-updates main restricted universe
+deb-src http://ports.ubuntu.com/ubuntu-ports/ zesty-updates main restricted universe
+
+deb http://ports.ubuntu.com/ubuntu-ports/ zesty-backports main restricted
+deb-src http://ports.ubuntu.com/ubuntu-ports/ zesty-backports main restricted
+
+deb http://ports.ubuntu.com/ubuntu-ports/ zesty-security main restricted universe multiverse
+deb-src http://ports.ubuntu.com/ubuntu-ports/ zesty-security main restricted universe multiverse
diff --git a/eng/common/cross/arm/trusty-lttng-2.4.patch b/eng/common/cross/arm/trusty-lttng-2.4.patch
new file mode 100644
index 000000000..8e4dd7ae7
--- /dev/null
+++ b/eng/common/cross/arm/trusty-lttng-2.4.patch
@@ -0,0 +1,71 @@
+From e72c9d7ead60e3317bd6d1fade995c07021c947b Mon Sep 17 00:00:00 2001
+From: Mathieu Desnoyers
+Date: Thu, 7 May 2015 13:25:04 -0400
+Subject: [PATCH] Fix: building probe providers with C++ compiler
+
+Robert Daniels wrote:
+> > I'm attempting to use lttng userspace tracing with a C++ application
+> > on an ARM platform. I'm using GCC 4.8.4 on Linux 3.14 with the 2.6
+> > release of lttng. I've compiled lttng-modules, lttng-ust, and
+> > lttng-tools and have been able to get a simple test working with C
+> > code. When I attempt to run the hello.cxx test on my target it will
+> > segfault.
+>
+>
+> I spent a little time digging into this issue and finally discovered the
+> cause of my segfault with ARM C++ tracepoints.
+>
+> There is a struct called 'lttng_event' in ust-events.h which contains an
+> empty union 'u'. This was the cause of my issue. Under C, this empty union
+> compiles to a zero byte member while under C++ it compiles to a one byte
+> member, and in my case was four-byte aligned which caused my C++ code to
+> have the 'cds_list_head node' offset incorrectly by four bytes. This lead
+> to an incorrect linked list structure which caused my issue.
+>
+> Since this union is empty, I simply removed it from the struct and everything
+> worked correctly.
+>
+> I don't know the history or purpose behind this empty union so I'd like to
+> know if this is a safe fix. If it is I can submit a patch with the union
+> removed.
+
+That's a very nice catch!
+
+We do not support building tracepoint probe provider with
+g++ yet, as stated in lttng-ust(3):
+
+"- Note for C++ support: although an application instrumented with
+ tracepoints can be compiled with g++, tracepoint probes should be
+ compiled with gcc (only tested with gcc so far)."
+
+However, if it works fine with this fix, then I'm tempted to take it,
+especially because removing the empty union does not appear to affect
+the layout of struct lttng_event as seen from liblttng-ust, which must
+be compiled with a C compiler, and from probe providers compiled with
+a C compiler. So all we are changing is the layout of a probe provider
+compiled with a C++ compiler, which is anyway buggy at the moment,
+because it is not compatible with the layout expected by liblttng-ust
+compiled with a C compiler.
+
+Reported-by: Robert Daniels
+Signed-off-by: Mathieu Desnoyers
+---
+ include/lttng/ust-events.h | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/usr/include/lttng/ust-events.h b/usr/include/lttng/ust-events.h
+index 328a875..3d7a274 100644
+--- a/usr/include/lttng/ust-events.h
++++ b/usr/include/lttng/ust-events.h
+@@ -407,8 +407,6 @@ struct lttng_event {
+ void *_deprecated1;
+ struct lttng_ctx *ctx;
+ enum lttng_ust_instrumentation instrumentation;
+- union {
+- } u;
+ struct cds_list_head node; /* Event list in session */
+ struct cds_list_head _deprecated2;
+ void *_deprecated3;
+--
+2.7.4
+
diff --git a/eng/common/cross/arm/trusty.patch b/eng/common/cross/arm/trusty.patch
new file mode 100644
index 000000000..2f2972f8e
--- /dev/null
+++ b/eng/common/cross/arm/trusty.patch
@@ -0,0 +1,97 @@
+diff -u -r a/usr/include/urcu/uatomic/generic.h b/usr/include/urcu/uatomic/generic.h
+--- a/usr/include/urcu/uatomic/generic.h 2014-03-28 06:04:42.000000000 +0900
++++ b/usr/include/urcu/uatomic/generic.h 2017-02-13 10:35:21.189927116 +0900
+@@ -65,17 +65,17 @@
+ switch (len) {
+ #ifdef UATOMIC_HAS_ATOMIC_BYTE
+ case 1:
+- return __sync_val_compare_and_swap_1(addr, old, _new);
++ return __sync_val_compare_and_swap_1((uint8_t *) addr, old, _new);
+ #endif
+ #ifdef UATOMIC_HAS_ATOMIC_SHORT
+ case 2:
+- return __sync_val_compare_and_swap_2(addr, old, _new);
++ return __sync_val_compare_and_swap_2((uint16_t *) addr, old, _new);
+ #endif
+ case 4:
+- return __sync_val_compare_and_swap_4(addr, old, _new);
++ return __sync_val_compare_and_swap_4((uint32_t *) addr, old, _new);
+ #if (CAA_BITS_PER_LONG == 64)
+ case 8:
+- return __sync_val_compare_and_swap_8(addr, old, _new);
++ return __sync_val_compare_and_swap_8((uint64_t *) addr, old, _new);
+ #endif
+ }
+ _uatomic_link_error();
+@@ -100,20 +100,20 @@
+ switch (len) {
+ #ifdef UATOMIC_HAS_ATOMIC_BYTE
+ case 1:
+- __sync_and_and_fetch_1(addr, val);
++ __sync_and_and_fetch_1((uint8_t *) addr, val);
+ return;
+ #endif
+ #ifdef UATOMIC_HAS_ATOMIC_SHORT
+ case 2:
+- __sync_and_and_fetch_2(addr, val);
++ __sync_and_and_fetch_2((uint16_t *) addr, val);
+ return;
+ #endif
+ case 4:
+- __sync_and_and_fetch_4(addr, val);
++ __sync_and_and_fetch_4((uint32_t *) addr, val);
+ return;
+ #if (CAA_BITS_PER_LONG == 64)
+ case 8:
+- __sync_and_and_fetch_8(addr, val);
++ __sync_and_and_fetch_8((uint64_t *) addr, val);
+ return;
+ #endif
+ }
+@@ -139,20 +139,20 @@
+ switch (len) {
+ #ifdef UATOMIC_HAS_ATOMIC_BYTE
+ case 1:
+- __sync_or_and_fetch_1(addr, val);
++ __sync_or_and_fetch_1((uint8_t *) addr, val);
+ return;
+ #endif
+ #ifdef UATOMIC_HAS_ATOMIC_SHORT
+ case 2:
+- __sync_or_and_fetch_2(addr, val);
++ __sync_or_and_fetch_2((uint16_t *) addr, val);
+ return;
+ #endif
+ case 4:
+- __sync_or_and_fetch_4(addr, val);
++ __sync_or_and_fetch_4((uint32_t *) addr, val);
+ return;
+ #if (CAA_BITS_PER_LONG == 64)
+ case 8:
+- __sync_or_and_fetch_8(addr, val);
++ __sync_or_and_fetch_8((uint64_t *) addr, val);
+ return;
+ #endif
+ }
+@@ -180,17 +180,17 @@
+ switch (len) {
+ #ifdef UATOMIC_HAS_ATOMIC_BYTE
+ case 1:
+- return __sync_add_and_fetch_1(addr, val);
++ return __sync_add_and_fetch_1((uint8_t *) addr, val);
+ #endif
+ #ifdef UATOMIC_HAS_ATOMIC_SHORT
+ case 2:
+- return __sync_add_and_fetch_2(addr, val);
++ return __sync_add_and_fetch_2((uint16_t *) addr, val);
+ #endif
+ case 4:
+- return __sync_add_and_fetch_4(addr, val);
++ return __sync_add_and_fetch_4((uint32_t *) addr, val);
+ #if (CAA_BITS_PER_LONG == 64)
+ case 8:
+- return __sync_add_and_fetch_8(addr, val);
++ return __sync_add_and_fetch_8((uint64_t *) addr, val);
+ #endif
+ }
+ _uatomic_link_error();
diff --git a/eng/common/cross/arm64/sources.list.bionic b/eng/common/cross/arm64/sources.list.bionic
new file mode 100644
index 000000000..210955740
--- /dev/null
+++ b/eng/common/cross/arm64/sources.list.bionic
@@ -0,0 +1,11 @@
+deb http://ports.ubuntu.com/ubuntu-ports/ bionic main restricted universe
+deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic main restricted universe
+
+deb http://ports.ubuntu.com/ubuntu-ports/ bionic-updates main restricted universe
+deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic-updates main restricted universe
+
+deb http://ports.ubuntu.com/ubuntu-ports/ bionic-backports main restricted
+deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic-backports main restricted
+
+deb http://ports.ubuntu.com/ubuntu-ports/ bionic-security main restricted universe multiverse
+deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic-security main restricted universe multiverse
diff --git a/eng/common/cross/arm64/sources.list.buster b/eng/common/cross/arm64/sources.list.buster
new file mode 100644
index 000000000..7194ac64a
--- /dev/null
+++ b/eng/common/cross/arm64/sources.list.buster
@@ -0,0 +1,11 @@
+deb http://deb.debian.org/debian buster main
+deb-src http://deb.debian.org/debian buster main
+
+deb http://deb.debian.org/debian-security/ buster/updates main
+deb-src http://deb.debian.org/debian-security/ buster/updates main
+
+deb http://deb.debian.org/debian buster-updates main
+deb-src http://deb.debian.org/debian buster-updates main
+
+deb http://deb.debian.org/debian buster-backports main contrib non-free
+deb-src http://deb.debian.org/debian buster-backports main contrib non-free
diff --git a/eng/common/cross/arm64/sources.list.stretch b/eng/common/cross/arm64/sources.list.stretch
new file mode 100644
index 000000000..0e1215774
--- /dev/null
+++ b/eng/common/cross/arm64/sources.list.stretch
@@ -0,0 +1,12 @@
+deb http://deb.debian.org/debian stretch main
+deb-src http://deb.debian.org/debian stretch main
+
+deb http://deb.debian.org/debian-security/ stretch/updates main
+deb-src http://deb.debian.org/debian-security/ stretch/updates main
+
+deb http://deb.debian.org/debian stretch-updates main
+deb-src http://deb.debian.org/debian stretch-updates main
+
+deb http://deb.debian.org/debian stretch-backports main contrib non-free
+deb-src http://deb.debian.org/debian stretch-backports main contrib non-free
+
diff --git a/eng/common/cross/arm64/sources.list.trusty b/eng/common/cross/arm64/sources.list.trusty
new file mode 100644
index 000000000..07d8f88d8
--- /dev/null
+++ b/eng/common/cross/arm64/sources.list.trusty
@@ -0,0 +1,11 @@
+deb http://ports.ubuntu.com/ubuntu-ports/ trusty main restricted universe
+deb-src http://ports.ubuntu.com/ubuntu-ports/ trusty main restricted universe
+
+deb http://ports.ubuntu.com/ubuntu-ports/ trusty-updates main restricted universe
+deb-src http://ports.ubuntu.com/ubuntu-ports/ trusty-updates main restricted universe
+
+deb http://ports.ubuntu.com/ubuntu-ports/ trusty-backports main restricted
+deb-src http://ports.ubuntu.com/ubuntu-ports/ trusty-backports main restricted
+
+deb http://ports.ubuntu.com/ubuntu-ports/ trusty-security main restricted universe multiverse
+deb-src http://ports.ubuntu.com/ubuntu-ports/ trusty-security main restricted universe multiverse
\ No newline at end of file
diff --git a/eng/common/cross/arm64/sources.list.xenial b/eng/common/cross/arm64/sources.list.xenial
new file mode 100644
index 000000000..eacd86b7d
--- /dev/null
+++ b/eng/common/cross/arm64/sources.list.xenial
@@ -0,0 +1,11 @@
+deb http://ports.ubuntu.com/ubuntu-ports/ xenial main restricted universe
+deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial main restricted universe
+
+deb http://ports.ubuntu.com/ubuntu-ports/ xenial-updates main restricted universe
+deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial-updates main restricted universe
+
+deb http://ports.ubuntu.com/ubuntu-ports/ xenial-backports main restricted
+deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial-backports main restricted
+
+deb http://ports.ubuntu.com/ubuntu-ports/ xenial-security main restricted universe multiverse
+deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial-security main restricted universe multiverse
\ No newline at end of file
diff --git a/eng/common/cross/arm64/sources.list.zesty b/eng/common/cross/arm64/sources.list.zesty
new file mode 100644
index 000000000..ea2c14a78
--- /dev/null
+++ b/eng/common/cross/arm64/sources.list.zesty
@@ -0,0 +1,11 @@
+deb http://ports.ubuntu.com/ubuntu-ports/ zesty main restricted universe
+deb-src http://ports.ubuntu.com/ubuntu-ports/ zesty main restricted universe
+
+deb http://ports.ubuntu.com/ubuntu-ports/ zesty-updates main restricted universe
+deb-src http://ports.ubuntu.com/ubuntu-ports/ zesty-updates main restricted universe
+
+deb http://ports.ubuntu.com/ubuntu-ports/ zesty-backports main restricted
+deb-src http://ports.ubuntu.com/ubuntu-ports/ zesty-backports main restricted
+
+deb http://ports.ubuntu.com/ubuntu-ports/ zesty-security main restricted universe multiverse
+deb-src http://ports.ubuntu.com/ubuntu-ports/ zesty-security main restricted universe multiverse
diff --git a/eng/common/cross/arm64/tizen-build-rootfs.sh b/eng/common/cross/arm64/tizen-build-rootfs.sh
new file mode 100644
index 000000000..13bfddb5e
--- /dev/null
+++ b/eng/common/cross/arm64/tizen-build-rootfs.sh
@@ -0,0 +1,35 @@
+#!/usr/bin/env bash
+set -e
+
+__CrossDir=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
+__TIZEN_CROSSDIR="$__CrossDir/tizen"
+
+if [[ -z "$ROOTFS_DIR" ]]; then
+ echo "ROOTFS_DIR is not defined."
+ exit 1;
+fi
+
+TIZEN_TMP_DIR=$ROOTFS_DIR/tizen_tmp
+mkdir -p $TIZEN_TMP_DIR
+
+# Download files
+echo ">>Start downloading files"
+VERBOSE=1 $__CrossDir/tizen-fetch.sh $TIZEN_TMP_DIR
+echo "<>Start constructing Tizen rootfs"
+TIZEN_RPM_FILES=`ls $TIZEN_TMP_DIR/*.rpm`
+cd $ROOTFS_DIR
+for f in $TIZEN_RPM_FILES; do
+ rpm2cpio $f | cpio -idm --quiet
+done
+echo "<>Start configuring Tizen rootfs"
+ln -sfn asm-arm64 ./usr/include/asm
+patch -p1 < $__TIZEN_CROSSDIR/tizen.patch
+echo "</dev/null; then
+ VERBOSE=0
+fi
+
+Log()
+{
+ if [ $VERBOSE -ge $1 ]; then
+ echo ${@:2}
+ fi
+}
+
+Inform()
+{
+ Log 1 -e "\x1B[0;34m$@\x1B[m"
+}
+
+Debug()
+{
+ Log 2 -e "\x1B[0;32m$@\x1B[m"
+}
+
+Error()
+{
+ >&2 Log 0 -e "\x1B[0;31m$@\x1B[m"
+}
+
+Fetch()
+{
+ URL=$1
+ FILE=$2
+ PROGRESS=$3
+ if [ $VERBOSE -ge 1 ] && [ $PROGRESS ]; then
+ CURL_OPT="--progress-bar"
+ else
+ CURL_OPT="--silent"
+ fi
+ curl $CURL_OPT $URL > $FILE
+}
+
+hash curl 2> /dev/null || { Error "Require 'curl' Aborting."; exit 1; }
+hash xmllint 2> /dev/null || { Error "Require 'xmllint' Aborting."; exit 1; }
+hash sha256sum 2> /dev/null || { Error "Require 'sha256sum' Aborting."; exit 1; }
+
+TMPDIR=$1
+if [ ! -d $TMPDIR ]; then
+ TMPDIR=./tizen_tmp
+ Debug "Create temporary directory : $TMPDIR"
+ mkdir -p $TMPDIR
+fi
+
+TIZEN_URL=http://download.tizen.org/snapshots/tizen/
+BUILD_XML=build.xml
+REPOMD_XML=repomd.xml
+PRIMARY_XML=primary.xml
+TARGET_URL="http://__not_initialized"
+
+Xpath_get()
+{
+ XPATH_RESULT=''
+ XPATH=$1
+ XML_FILE=$2
+ RESULT=$(xmllint --xpath $XPATH $XML_FILE)
+ if [[ -z ${RESULT// } ]]; then
+ Error "Can not find target from $XML_FILE"
+ Debug "Xpath = $XPATH"
+ exit 1
+ fi
+ XPATH_RESULT=$RESULT
+}
+
+fetch_tizen_pkgs_init()
+{
+ TARGET=$1
+ PROFILE=$2
+ Debug "Initialize TARGET=$TARGET, PROFILE=$PROFILE"
+
+ TMP_PKG_DIR=$TMPDIR/tizen_${PROFILE}_pkgs
+ if [ -d $TMP_PKG_DIR ]; then rm -rf $TMP_PKG_DIR; fi
+ mkdir -p $TMP_PKG_DIR
+
+ PKG_URL=$TIZEN_URL/$PROFILE/latest
+
+ BUILD_XML_URL=$PKG_URL/$BUILD_XML
+ TMP_BUILD=$TMP_PKG_DIR/$BUILD_XML
+ TMP_REPOMD=$TMP_PKG_DIR/$REPOMD_XML
+ TMP_PRIMARY=$TMP_PKG_DIR/$PRIMARY_XML
+ TMP_PRIMARYGZ=${TMP_PRIMARY}.gz
+
+ Fetch $BUILD_XML_URL $TMP_BUILD
+
+ Debug "fetch $BUILD_XML_URL to $TMP_BUILD"
+
+ TARGET_XPATH="//build/buildtargets/buildtarget[@name=\"$TARGET\"]/repo[@type=\"binary\"]/text()"
+ Xpath_get $TARGET_XPATH $TMP_BUILD
+ TARGET_PATH=$XPATH_RESULT
+ TARGET_URL=$PKG_URL/$TARGET_PATH
+
+ REPOMD_URL=$TARGET_URL/repodata/repomd.xml
+ PRIMARY_XPATH='string(//*[local-name()="data"][@type="primary"]/*[local-name()="location"]/@href)'
+
+ Fetch $REPOMD_URL $TMP_REPOMD
+
+ Debug "fetch $REPOMD_URL to $TMP_REPOMD"
+
+ Xpath_get $PRIMARY_XPATH $TMP_REPOMD
+ PRIMARY_XML_PATH=$XPATH_RESULT
+ PRIMARY_URL=$TARGET_URL/$PRIMARY_XML_PATH
+
+ Fetch $PRIMARY_URL $TMP_PRIMARYGZ
+
+ Debug "fetch $PRIMARY_URL to $TMP_PRIMARYGZ"
+
+ gunzip $TMP_PRIMARYGZ
+
+ Debug "unzip $TMP_PRIMARYGZ to $TMP_PRIMARY"
+}
+
+fetch_tizen_pkgs()
+{
+ ARCH=$1
+ PACKAGE_XPATH_TPL='string(//*[local-name()="metadata"]/*[local-name()="package"][*[local-name()="name"][text()="_PKG_"]][*[local-name()="arch"][text()="_ARCH_"]]/*[local-name()="location"]/@href)'
+
+ PACKAGE_CHECKSUM_XPATH_TPL='string(//*[local-name()="metadata"]/*[local-name()="package"][*[local-name()="name"][text()="_PKG_"]][*[local-name()="arch"][text()="_ARCH_"]]/*[local-name()="checksum"]/text())'
+
+ for pkg in ${@:2}
+ do
+ Inform "Fetching... $pkg"
+ XPATH=${PACKAGE_XPATH_TPL/_PKG_/$pkg}
+ XPATH=${XPATH/_ARCH_/$ARCH}
+ Xpath_get $XPATH $TMP_PRIMARY
+ PKG_PATH=$XPATH_RESULT
+
+ XPATH=${PACKAGE_CHECKSUM_XPATH_TPL/_PKG_/$pkg}
+ XPATH=${XPATH/_ARCH_/$ARCH}
+ Xpath_get $XPATH $TMP_PRIMARY
+ CHECKSUM=$XPATH_RESULT
+
+ PKG_URL=$TARGET_URL/$PKG_PATH
+ PKG_FILE=$(basename $PKG_PATH)
+ PKG_PATH=$TMPDIR/$PKG_FILE
+
+ Debug "Download $PKG_URL to $PKG_PATH"
+ Fetch $PKG_URL $PKG_PATH true
+
+ echo "$CHECKSUM $PKG_PATH" | sha256sum -c - > /dev/null
+ if [ $? -ne 0 ]; then
+ Error "Fail to fetch $PKG_URL to $PKG_PATH"
+ Debug "Checksum = $CHECKSUM"
+ exit 1
+ fi
+ done
+}
+
+Inform "Initialize arm base"
+fetch_tizen_pkgs_init standard base
+Inform "fetch common packages"
+fetch_tizen_pkgs aarch64 gcc glibc glibc-devel libicu libicu-devel libatomic linux-glibc-devel keyutils keyutils-devel libkeyutils
+Inform "fetch coreclr packages"
+fetch_tizen_pkgs aarch64 lldb lldb-devel libgcc libstdc++ libstdc++-devel libunwind libunwind-devel lttng-ust-devel lttng-ust userspace-rcu-devel userspace-rcu
+Inform "fetch corefx packages"
+fetch_tizen_pkgs aarch64 libcom_err libcom_err-devel zlib zlib-devel libopenssl11 libopenssl1.1-devel krb5 krb5-devel
+
+Inform "Initialize standard unified"
+fetch_tizen_pkgs_init standard unified
+Inform "fetch corefx packages"
+fetch_tizen_pkgs aarch64 gssdp gssdp-devel tizen-release
+
diff --git a/eng/common/cross/arm64/tizen/tizen.patch b/eng/common/cross/arm64/tizen/tizen.patch
new file mode 100644
index 000000000..af7c8be05
--- /dev/null
+++ b/eng/common/cross/arm64/tizen/tizen.patch
@@ -0,0 +1,9 @@
+diff -u -r a/usr/lib/libc.so b/usr/lib/libc.so
+--- a/usr/lib64/libc.so 2016-12-30 23:00:08.284951863 +0900
++++ b/usr/lib64/libc.so 2016-12-30 23:00:32.140951815 +0900
+@@ -2,4 +2,4 @@
+ Use the shared library, but some functions are only in
+ the static library, so try that secondarily. */
+ OUTPUT_FORMAT(elf64-littleaarch64)
+-GROUP ( /lib64/libc.so.6 /usr/lib64/libc_nonshared.a AS_NEEDED ( /lib/ld-linux-aarch64.so.1 ) )
++GROUP ( libc.so.6 libc_nonshared.a AS_NEEDED ( ld-linux-aarch64.so.1 ) )
diff --git a/eng/common/cross/armel/armel.jessie.patch b/eng/common/cross/armel/armel.jessie.patch
new file mode 100644
index 000000000..2d2615619
--- /dev/null
+++ b/eng/common/cross/armel/armel.jessie.patch
@@ -0,0 +1,43 @@
+diff -u -r a/usr/include/urcu/uatomic/generic.h b/usr/include/urcu/uatomic/generic.h
+--- a/usr/include/urcu/uatomic/generic.h 2014-10-22 15:00:58.000000000 -0700
++++ b/usr/include/urcu/uatomic/generic.h 2020-10-30 21:38:28.550000000 -0700
+@@ -69,10 +69,10 @@
+ #endif
+ #ifdef UATOMIC_HAS_ATOMIC_SHORT
+ case 2:
+- return __sync_val_compare_and_swap_2(addr, old, _new);
++ return __sync_val_compare_and_swap_2((uint16_t*) addr, old, _new);
+ #endif
+ case 4:
+- return __sync_val_compare_and_swap_4(addr, old, _new);
++ return __sync_val_compare_and_swap_4((uint32_t*) addr, old, _new);
+ #if (CAA_BITS_PER_LONG == 64)
+ case 8:
+ return __sync_val_compare_and_swap_8(addr, old, _new);
+@@ -109,7 +109,7 @@
+ return;
+ #endif
+ case 4:
+- __sync_and_and_fetch_4(addr, val);
++ __sync_and_and_fetch_4((uint32_t*) addr, val);
+ return;
+ #if (CAA_BITS_PER_LONG == 64)
+ case 8:
+@@ -148,7 +148,7 @@
+ return;
+ #endif
+ case 4:
+- __sync_or_and_fetch_4(addr, val);
++ __sync_or_and_fetch_4((uint32_t*) addr, val);
+ return;
+ #if (CAA_BITS_PER_LONG == 64)
+ case 8:
+@@ -187,7 +187,7 @@
+ return __sync_add_and_fetch_2(addr, val);
+ #endif
+ case 4:
+- return __sync_add_and_fetch_4(addr, val);
++ return __sync_add_and_fetch_4((uint32_t*) addr, val);
+ #if (CAA_BITS_PER_LONG == 64)
+ case 8:
+ return __sync_add_and_fetch_8(addr, val);
diff --git a/eng/common/cross/armel/sources.list.jessie b/eng/common/cross/armel/sources.list.jessie
new file mode 100644
index 000000000..3d9c3059d
--- /dev/null
+++ b/eng/common/cross/armel/sources.list.jessie
@@ -0,0 +1,3 @@
+# Debian (jessie) # Stable
+deb http://ftp.debian.org/debian/ jessie main contrib non-free
+deb-src http://ftp.debian.org/debian/ jessie main contrib non-free
diff --git a/eng/common/cross/armel/tizen-build-rootfs.sh b/eng/common/cross/armel/tizen-build-rootfs.sh
new file mode 100644
index 000000000..9a4438af6
--- /dev/null
+++ b/eng/common/cross/armel/tizen-build-rootfs.sh
@@ -0,0 +1,35 @@
+#!/usr/bin/env bash
+set -e
+
+__ARM_SOFTFP_CrossDir=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
+__TIZEN_CROSSDIR="$__ARM_SOFTFP_CrossDir/tizen"
+
+if [[ -z "$ROOTFS_DIR" ]]; then
+ echo "ROOTFS_DIR is not defined."
+ exit 1;
+fi
+
+TIZEN_TMP_DIR=$ROOTFS_DIR/tizen_tmp
+mkdir -p $TIZEN_TMP_DIR
+
+# Download files
+echo ">>Start downloading files"
+VERBOSE=1 $__ARM_SOFTFP_CrossDir/tizen-fetch.sh $TIZEN_TMP_DIR
+echo "<>Start constructing Tizen rootfs"
+TIZEN_RPM_FILES=`ls $TIZEN_TMP_DIR/*.rpm`
+cd $ROOTFS_DIR
+for f in $TIZEN_RPM_FILES; do
+ rpm2cpio $f | cpio -idm --quiet
+done
+echo "<>Start configuring Tizen rootfs"
+ln -sfn asm-arm ./usr/include/asm
+patch -p1 < $__TIZEN_CROSSDIR/tizen.patch
+echo "</dev/null; then
+ VERBOSE=0
+fi
+
+Log()
+{
+ if [ $VERBOSE -ge $1 ]; then
+ echo ${@:2}
+ fi
+}
+
+Inform()
+{
+ Log 1 -e "\x1B[0;34m$@\x1B[m"
+}
+
+Debug()
+{
+ Log 2 -e "\x1B[0;32m$@\x1B[m"
+}
+
+Error()
+{
+ >&2 Log 0 -e "\x1B[0;31m$@\x1B[m"
+}
+
+Fetch()
+{
+ URL=$1
+ FILE=$2
+ PROGRESS=$3
+ if [ $VERBOSE -ge 1 ] && [ $PROGRESS ]; then
+ CURL_OPT="--progress-bar"
+ else
+ CURL_OPT="--silent"
+ fi
+ curl $CURL_OPT $URL > $FILE
+}
+
+hash curl 2> /dev/null || { Error "Require 'curl' Aborting."; exit 1; }
+hash xmllint 2> /dev/null || { Error "Require 'xmllint' Aborting."; exit 1; }
+hash sha256sum 2> /dev/null || { Error "Require 'sha256sum' Aborting."; exit 1; }
+
+TMPDIR=$1
+if [ ! -d $TMPDIR ]; then
+ TMPDIR=./tizen_tmp
+ Debug "Create temporary directory : $TMPDIR"
+ mkdir -p $TMPDIR
+fi
+
+TIZEN_URL=http://download.tizen.org/snapshots/tizen
+BUILD_XML=build.xml
+REPOMD_XML=repomd.xml
+PRIMARY_XML=primary.xml
+TARGET_URL="http://__not_initialized"
+
+Xpath_get()
+{
+ XPATH_RESULT=''
+ XPATH=$1
+ XML_FILE=$2
+ RESULT=$(xmllint --xpath $XPATH $XML_FILE)
+ if [[ -z ${RESULT// } ]]; then
+ Error "Can not find target from $XML_FILE"
+ Debug "Xpath = $XPATH"
+ exit 1
+ fi
+ XPATH_RESULT=$RESULT
+}
+
+fetch_tizen_pkgs_init()
+{
+ TARGET=$1
+ PROFILE=$2
+ Debug "Initialize TARGET=$TARGET, PROFILE=$PROFILE"
+
+ TMP_PKG_DIR=$TMPDIR/tizen_${PROFILE}_pkgs
+ if [ -d $TMP_PKG_DIR ]; then rm -rf $TMP_PKG_DIR; fi
+ mkdir -p $TMP_PKG_DIR
+
+ PKG_URL=$TIZEN_URL/$PROFILE/latest
+
+ BUILD_XML_URL=$PKG_URL/$BUILD_XML
+ TMP_BUILD=$TMP_PKG_DIR/$BUILD_XML
+ TMP_REPOMD=$TMP_PKG_DIR/$REPOMD_XML
+ TMP_PRIMARY=$TMP_PKG_DIR/$PRIMARY_XML
+ TMP_PRIMARYGZ=${TMP_PRIMARY}.gz
+
+ Fetch $BUILD_XML_URL $TMP_BUILD
+
+ Debug "fetch $BUILD_XML_URL to $TMP_BUILD"
+
+ TARGET_XPATH="//build/buildtargets/buildtarget[@name=\"$TARGET\"]/repo[@type=\"binary\"]/text()"
+ Xpath_get $TARGET_XPATH $TMP_BUILD
+ TARGET_PATH=$XPATH_RESULT
+ TARGET_URL=$PKG_URL/$TARGET_PATH
+
+ REPOMD_URL=$TARGET_URL/repodata/repomd.xml
+ PRIMARY_XPATH='string(//*[local-name()="data"][@type="primary"]/*[local-name()="location"]/@href)'
+
+ Fetch $REPOMD_URL $TMP_REPOMD
+
+ Debug "fetch $REPOMD_URL to $TMP_REPOMD"
+
+ Xpath_get $PRIMARY_XPATH $TMP_REPOMD
+ PRIMARY_XML_PATH=$XPATH_RESULT
+ PRIMARY_URL=$TARGET_URL/$PRIMARY_XML_PATH
+
+ Fetch $PRIMARY_URL $TMP_PRIMARYGZ
+
+ Debug "fetch $PRIMARY_URL to $TMP_PRIMARYGZ"
+
+ gunzip $TMP_PRIMARYGZ
+
+ Debug "unzip $TMP_PRIMARYGZ to $TMP_PRIMARY"
+}
+
+fetch_tizen_pkgs()
+{
+ ARCH=$1
+ PACKAGE_XPATH_TPL='string(//*[local-name()="metadata"]/*[local-name()="package"][*[local-name()="name"][text()="_PKG_"]][*[local-name()="arch"][text()="_ARCH_"]]/*[local-name()="location"]/@href)'
+
+ PACKAGE_CHECKSUM_XPATH_TPL='string(//*[local-name()="metadata"]/*[local-name()="package"][*[local-name()="name"][text()="_PKG_"]][*[local-name()="arch"][text()="_ARCH_"]]/*[local-name()="checksum"]/text())'
+
+ for pkg in ${@:2}
+ do
+ Inform "Fetching... $pkg"
+ XPATH=${PACKAGE_XPATH_TPL/_PKG_/$pkg}
+ XPATH=${XPATH/_ARCH_/$ARCH}
+ Xpath_get $XPATH $TMP_PRIMARY
+ PKG_PATH=$XPATH_RESULT
+
+ XPATH=${PACKAGE_CHECKSUM_XPATH_TPL/_PKG_/$pkg}
+ XPATH=${XPATH/_ARCH_/$ARCH}
+ Xpath_get $XPATH $TMP_PRIMARY
+ CHECKSUM=$XPATH_RESULT
+
+ PKG_URL=$TARGET_URL/$PKG_PATH
+ PKG_FILE=$(basename $PKG_PATH)
+ PKG_PATH=$TMPDIR/$PKG_FILE
+
+ Debug "Download $PKG_URL to $PKG_PATH"
+ Fetch $PKG_URL $PKG_PATH true
+
+ echo "$CHECKSUM $PKG_PATH" | sha256sum -c - > /dev/null
+ if [ $? -ne 0 ]; then
+ Error "Fail to fetch $PKG_URL to $PKG_PATH"
+ Debug "Checksum = $CHECKSUM"
+ exit 1
+ fi
+ done
+}
+
+Inform "Initialize arm base"
+fetch_tizen_pkgs_init standard base
+Inform "fetch common packages"
+fetch_tizen_pkgs armv7l gcc gcc-devel-static glibc glibc-devel libicu libicu-devel libatomic linux-glibc-devel keyutils keyutils-devel libkeyutils
+Inform "fetch coreclr packages"
+fetch_tizen_pkgs armv7l lldb lldb-devel libgcc libstdc++ libstdc++-devel libunwind libunwind-devel lttng-ust-devel lttng-ust userspace-rcu-devel userspace-rcu
+Inform "fetch corefx packages"
+fetch_tizen_pkgs armv7l libcom_err libcom_err-devel zlib zlib-devel libopenssl11 libopenssl1.1-devel krb5 krb5-devel
+
+Inform "Initialize standard unified"
+fetch_tizen_pkgs_init standard unified
+Inform "fetch corefx packages"
+fetch_tizen_pkgs armv7l gssdp gssdp-devel tizen-release
+
diff --git a/eng/common/cross/armel/tizen/tizen-dotnet.ks b/eng/common/cross/armel/tizen/tizen-dotnet.ks
new file mode 100644
index 000000000..506d455bd
--- /dev/null
+++ b/eng/common/cross/armel/tizen/tizen-dotnet.ks
@@ -0,0 +1,50 @@
+lang en_US.UTF-8
+keyboard us
+timezone --utc Asia/Seoul
+
+part / --fstype="ext4" --size=3500 --ondisk=mmcblk0 --label rootfs --fsoptions=defaults,noatime
+
+rootpw tizen
+desktop --autologinuser=root
+user --name root --groups audio,video --password 'tizen'
+
+repo --name=standard --baseurl=http://download.tizen.org/releases/milestone/tizen/unified/latest/repos/standard/packages/ --ssl_verify=no
+repo --name=base --baseurl=http://download.tizen.org/releases/milestone/tizen/base/latest/repos/standard/packages/ --ssl_verify=no
+
+%packages
+tar
+gzip
+
+sed
+grep
+gawk
+perl
+
+binutils
+findutils
+util-linux
+lttng-ust
+userspace-rcu
+procps-ng
+tzdata
+ca-certificates
+
+
+### Core FX
+libicu
+libunwind
+iputils
+zlib
+krb5
+libcurl
+libopenssl
+
+%end
+
+%post
+
+### Update /tmp privilege
+chmod 777 /tmp
+####################################
+
+%end
diff --git a/eng/common/cross/armel/tizen/tizen.patch b/eng/common/cross/armel/tizen/tizen.patch
new file mode 100644
index 000000000..ca7c7c1ff
--- /dev/null
+++ b/eng/common/cross/armel/tizen/tizen.patch
@@ -0,0 +1,9 @@
+diff -u -r a/usr/lib/libc.so b/usr/lib/libc.so
+--- a/usr/lib/libc.so 2016-12-30 23:00:08.284951863 +0900
++++ b/usr/lib/libc.so 2016-12-30 23:00:32.140951815 +0900
+@@ -2,4 +2,4 @@
+ Use the shared library, but some functions are only in
+ the static library, so try that secondarily. */
+ OUTPUT_FORMAT(elf32-littlearm)
+-GROUP ( /lib/libc.so.6 /usr/lib/libc_nonshared.a AS_NEEDED ( /lib/ld-linux.so.3 ) )
++GROUP ( libc.so.6 libc_nonshared.a AS_NEEDED ( ld-linux.so.3 ) )
diff --git a/eng/common/cross/build-android-rootfs.sh b/eng/common/cross/build-android-rootfs.sh
new file mode 100644
index 000000000..42516bbee
--- /dev/null
+++ b/eng/common/cross/build-android-rootfs.sh
@@ -0,0 +1,131 @@
+#!/usr/bin/env bash
+set -e
+__NDK_Version=r21
+
+usage()
+{
+ echo "Creates a toolchain and sysroot used for cross-compiling for Android."
+ echo.
+ echo "Usage: $0 [BuildArch] [ApiLevel]"
+ echo.
+ echo "BuildArch is the target architecture of Android. Currently only arm64 is supported."
+ echo "ApiLevel is the target Android API level. API levels usually match to Android releases. See https://source.android.com/source/build-numbers.html"
+ echo.
+ echo "By default, the toolchain and sysroot will be generated in cross/android-rootfs/toolchain/[BuildArch]. You can change this behavior"
+ echo "by setting the TOOLCHAIN_DIR environment variable"
+ echo.
+ echo "By default, the NDK will be downloaded into the cross/android-rootfs/android-ndk-$__NDK_Version directory. If you already have an NDK installation,"
+ echo "you can set the NDK_DIR environment variable to have this script use that installation of the NDK."
+ echo "By default, this script will generate a file, android_platform, in the root of the ROOTFS_DIR directory that contains the RID for the supported and tested Android build: android.28-arm64. This file is to replace '/etc/os-release', which is not available for Android."
+ exit 1
+}
+
+__ApiLevel=28 # The minimum platform for arm64 is API level 21 but the minimum version that support glob(3) is 28. See $ANDROID_NDK/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/include/glob.h
+__BuildArch=arm64
+__AndroidArch=aarch64
+__AndroidToolchain=aarch64-linux-android
+
+for i in "$@"
+ do
+ lowerI="$(echo $i | tr "[:upper:]" "[:lower:]")"
+ case $lowerI in
+ -?|-h|--help)
+ usage
+ exit 1
+ ;;
+ arm64)
+ __BuildArch=arm64
+ __AndroidArch=aarch64
+ __AndroidToolchain=aarch64-linux-android
+ ;;
+ arm)
+ __BuildArch=arm
+ __AndroidArch=arm
+ __AndroidToolchain=arm-linux-androideabi
+ ;;
+ *[0-9])
+ __ApiLevel=$i
+ ;;
+ *)
+ __UnprocessedBuildArgs="$__UnprocessedBuildArgs $i"
+ ;;
+ esac
+done
+
+# Obtain the location of the bash script to figure out where the root of the repo is.
+__ScriptBaseDir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
+
+__CrossDir="$__ScriptBaseDir/../../../.tools/android-rootfs"
+
+if [[ ! -f "$__CrossDir" ]]; then
+ mkdir -p "$__CrossDir"
+fi
+
+# Resolve absolute path to avoid `../` in build logs
+__CrossDir="$( cd "$__CrossDir" && pwd )"
+
+__NDK_Dir="$__CrossDir/android-ndk-$__NDK_Version"
+__lldb_Dir="$__CrossDir/lldb"
+__ToolchainDir="$__CrossDir/android-ndk-$__NDK_Version"
+
+if [[ -n "$TOOLCHAIN_DIR" ]]; then
+ __ToolchainDir=$TOOLCHAIN_DIR
+fi
+
+if [[ -n "$NDK_DIR" ]]; then
+ __NDK_Dir=$NDK_DIR
+fi
+
+echo "Target API level: $__ApiLevel"
+echo "Target architecture: $__BuildArch"
+echo "NDK location: $__NDK_Dir"
+echo "Target Toolchain location: $__ToolchainDir"
+
+# Download the NDK if required
+if [ ! -d $__NDK_Dir ]; then
+ echo Downloading the NDK into $__NDK_Dir
+ mkdir -p $__NDK_Dir
+ wget -q --progress=bar:force:noscroll --show-progress https://dl.google.com/android/repository/android-ndk-$__NDK_Version-linux-x86_64.zip -O $__CrossDir/android-ndk-$__NDK_Version-linux-x86_64.zip
+ unzip -q $__CrossDir/android-ndk-$__NDK_Version-linux-x86_64.zip -d $__CrossDir
+fi
+
+if [ ! -d $__lldb_Dir ]; then
+ mkdir -p $__lldb_Dir
+ echo Downloading LLDB into $__lldb_Dir
+ wget -q --progress=bar:force:noscroll --show-progress https://dl.google.com/android/repository/lldb-2.3.3614996-linux-x86_64.zip -O $__CrossDir/lldb-2.3.3614996-linux-x86_64.zip
+ unzip -q $__CrossDir/lldb-2.3.3614996-linux-x86_64.zip -d $__lldb_Dir
+fi
+
+echo "Download dependencies..."
+__TmpDir=$__CrossDir/tmp/$__BuildArch/
+mkdir -p "$__TmpDir"
+
+# combined dependencies for coreclr, installer and libraries
+__AndroidPackages="libicu"
+__AndroidPackages+=" libandroid-glob"
+__AndroidPackages+=" liblzma"
+__AndroidPackages+=" krb5"
+__AndroidPackages+=" openssl"
+
+for path in $(wget -qO- http://termux.net/dists/stable/main/binary-$__AndroidArch/Packages |\
+ grep -A15 "Package: \(${__AndroidPackages// /\\|}\)" | grep -v "static\|tool" | grep Filename); do
+
+ if [[ "$path" != "Filename:" ]]; then
+ echo "Working on: $path"
+ wget -qO- http://termux.net/$path | dpkg -x - "$__TmpDir"
+ fi
+done
+
+cp -R "$__TmpDir/data/data/com.termux/files/usr/"* "$__ToolchainDir/sysroot/usr/"
+
+# Generate platform file for build.sh script to assign to __DistroRid
+echo "Generating platform file..."
+echo "RID=android.${__ApiLevel}-${__BuildArch}" > $__ToolchainDir/sysroot/android_platform
+
+echo "Now to build coreclr, libraries and installers; run:"
+echo ROOTFS_DIR=\$\(realpath $__ToolchainDir/sysroot\) ./build.sh --cross --arch $__BuildArch \
+ --subsetCategory coreclr
+echo ROOTFS_DIR=\$\(realpath $__ToolchainDir/sysroot\) ./build.sh --cross --arch $__BuildArch \
+ --subsetCategory libraries
+echo ROOTFS_DIR=\$\(realpath $__ToolchainDir/sysroot\) ./build.sh --cross --arch $__BuildArch \
+ --subsetCategory installer
diff --git a/eng/common/cross/build-rootfs.sh b/eng/common/cross/build-rootfs.sh
new file mode 100644
index 000000000..735a4c828
--- /dev/null
+++ b/eng/common/cross/build-rootfs.sh
@@ -0,0 +1,385 @@
+#!/usr/bin/env bash
+
+set -e
+
+usage()
+{
+ echo "Usage: $0 [BuildArch] [CodeName] [lldbx.y] [--skipunmount] --rootfsdir ]"
+ echo "BuildArch can be: arm(default), armel, arm64, x86"
+ echo "CodeName - optional, Code name for Linux, can be: trusty, xenial(default), zesty, bionic, alpine, alpine3.9 or alpine3.13. If BuildArch is armel, LinuxCodeName is jessie(default) or tizen."
+ echo " for FreeBSD can be: freebsd11 or freebsd12."
+ echo " for illumos can be: illumos."
+ echo "lldbx.y - optional, LLDB version, can be: lldb3.9(default), lldb4.0, lldb5.0, lldb6.0 no-lldb. Ignored for alpine and FReeBSD"
+ echo "--skipunmount - optional, will skip the unmount of rootfs folder."
+ echo "--use-mirror - optional, use mirror URL to fetch resources, when available."
+ exit 1
+}
+
+__CodeName=xenial
+__CrossDir=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
+__InitialDir=$PWD
+__BuildArch=arm
+__AlpineArch=armv7
+__QEMUArch=arm
+__UbuntuArch=armhf
+__UbuntuRepo="http://ports.ubuntu.com/"
+__LLDB_Package="liblldb-3.9-dev"
+__SkipUnmount=0
+
+# base development support
+__UbuntuPackages="build-essential"
+
+__AlpinePackages="alpine-base"
+__AlpinePackages+=" build-base"
+__AlpinePackages+=" linux-headers"
+__AlpinePackagesEdgeCommunity=" lldb-dev"
+__AlpinePackagesEdgeMain+=" python3"
+__AlpinePackagesEdgeMain+=" libedit"
+
+# symlinks fixer
+__UbuntuPackages+=" symlinks"
+
+# CoreCLR and CoreFX dependencies
+__UbuntuPackages+=" libicu-dev"
+__UbuntuPackages+=" liblttng-ust-dev"
+__UbuntuPackages+=" libunwind8-dev"
+
+__AlpinePackages+=" gettext-dev"
+__AlpinePackages+=" icu-dev"
+__AlpinePackages+=" libunwind-dev"
+__AlpinePackages+=" lttng-ust-dev"
+
+# CoreFX dependencies
+__UbuntuPackages+=" libcurl4-openssl-dev"
+__UbuntuPackages+=" libkrb5-dev"
+__UbuntuPackages+=" libssl-dev"
+__UbuntuPackages+=" zlib1g-dev"
+
+__AlpinePackages+=" curl-dev"
+__AlpinePackages+=" krb5-dev"
+__AlpinePackages+=" openssl-dev"
+__AlpinePackages+=" zlib-dev"
+
+__FreeBSDBase="12.1-RELEASE"
+__FreeBSDPkg="1.12.0"
+__FreeBSDPackages="libunwind"
+__FreeBSDPackages+=" icu"
+__FreeBSDPackages+=" libinotify"
+__FreeBSDPackages+=" lttng-ust"
+__FreeBSDPackages+=" krb5"
+
+__IllumosPackages="icu-64.2nb2"
+__IllumosPackages+=" mit-krb5-1.16.2nb4"
+__IllumosPackages+=" openssl-1.1.1e"
+__IllumosPackages+=" zlib-1.2.11"
+
+# ML.NET dependencies
+__UbuntuPackages+=" libomp5"
+__UbuntuPackages+=" libomp-dev"
+
+__UseMirror=0
+
+__UnprocessedBuildArgs=
+while :; do
+ if [ $# -le 0 ]; then
+ break
+ fi
+
+ lowerI="$(echo $1 | tr "[:upper:]" "[:lower:]")"
+ case $lowerI in
+ -?|-h|--help)
+ usage
+ exit 1
+ ;;
+ arm)
+ __BuildArch=arm
+ __UbuntuArch=armhf
+ __AlpineArch=armv7
+ __QEMUArch=arm
+ ;;
+ arm64)
+ __BuildArch=arm64
+ __UbuntuArch=arm64
+ __AlpineArch=aarch64
+ __QEMUArch=aarch64
+ ;;
+ armel)
+ __BuildArch=armel
+ __UbuntuArch=armel
+ __UbuntuRepo="http://ftp.debian.org/debian/"
+ __CodeName=jessie
+ ;;
+ s390x)
+ __BuildArch=s390x
+ __UbuntuArch=s390x
+ __UbuntuRepo="http://ports.ubuntu.com/ubuntu-ports/"
+ __UbuntuPackages=$(echo ${__UbuntuPackages} | sed 's/ libunwind8-dev//')
+ __UbuntuPackages=$(echo ${__UbuntuPackages} | sed 's/ libomp-dev//')
+ __UbuntuPackages=$(echo ${__UbuntuPackages} | sed 's/ libomp5//')
+ unset __LLDB_Package
+ ;;
+ x86)
+ __BuildArch=x86
+ __UbuntuArch=i386
+ __UbuntuRepo="http://archive.ubuntu.com/ubuntu/"
+ ;;
+ lldb3.6)
+ __LLDB_Package="lldb-3.6-dev"
+ ;;
+ lldb3.8)
+ __LLDB_Package="lldb-3.8-dev"
+ ;;
+ lldb3.9)
+ __LLDB_Package="liblldb-3.9-dev"
+ ;;
+ lldb4.0)
+ __LLDB_Package="liblldb-4.0-dev"
+ ;;
+ lldb5.0)
+ __LLDB_Package="liblldb-5.0-dev"
+ ;;
+ lldb6.0)
+ __LLDB_Package="liblldb-6.0-dev"
+ ;;
+ no-lldb)
+ unset __LLDB_Package
+ ;;
+ trusty) # Ubuntu 14.04
+ if [ "$__CodeName" != "jessie" ]; then
+ __CodeName=trusty
+ fi
+ ;;
+ xenial) # Ubuntu 16.04
+ if [ "$__CodeName" != "jessie" ]; then
+ __CodeName=xenial
+ fi
+ ;;
+ zesty) # Ubuntu 17.04
+ if [ "$__CodeName" != "jessie" ]; then
+ __CodeName=zesty
+ fi
+ ;;
+ bionic) # Ubuntu 18.04
+ if [ "$__CodeName" != "jessie" ]; then
+ __CodeName=bionic
+ fi
+ ;;
+ jessie) # Debian 8
+ __CodeName=jessie
+ __UbuntuRepo="http://ftp.debian.org/debian/"
+ ;;
+ stretch) # Debian 9
+ __CodeName=stretch
+ __UbuntuRepo="http://ftp.debian.org/debian/"
+ __LLDB_Package="liblldb-6.0-dev"
+ ;;
+ buster) # Debian 10
+ __CodeName=buster
+ __UbuntuRepo="http://ftp.debian.org/debian/"
+ __LLDB_Package="liblldb-6.0-dev"
+ ;;
+ tizen)
+ if [ "$__BuildArch" != "armel" ] && [ "$__BuildArch" != "arm64" ]; then
+ echo "Tizen is available only for armel and arm64."
+ usage;
+ exit 1;
+ fi
+ __CodeName=
+ __UbuntuRepo=
+ __Tizen=tizen
+ ;;
+ alpine|alpine3.9)
+ __CodeName=alpine
+ __UbuntuRepo=
+ __AlpineVersion=3.9
+ __AlpinePackagesEdgeMain+=" llvm11-libs"
+ __AlpinePackagesEdgeMain+=" clang-libs"
+ ;;
+ alpine3.13)
+ __CodeName=alpine
+ __UbuntuRepo=
+ __AlpineVersion=3.13
+ # Alpine 3.13 has all the packages we need in the 3.13 repository
+ __AlpinePackages+=$__AlpinePackagesEdgeCommunity
+ __AlpinePackagesEdgeCommunity=
+ __AlpinePackages+=$__AlpinePackagesEdgeMain
+ __AlpinePackagesEdgeMain=
+ __AlpinePackages+=" llvm10-libs"
+ ;;
+ freebsd11)
+ __FreeBSDBase="11.3-RELEASE"
+ ;&
+ freebsd12)
+ __CodeName=freebsd
+ __BuildArch=x64
+ __SkipUnmount=1
+ ;;
+ illumos)
+ __CodeName=illumos
+ __BuildArch=x64
+ __SkipUnmount=1
+ ;;
+ --skipunmount)
+ __SkipUnmount=1
+ ;;
+ --rootfsdir|-rootfsdir)
+ shift
+ __RootfsDir=$1
+ ;;
+ --use-mirror)
+ __UseMirror=1
+ ;;
+ *)
+ __UnprocessedBuildArgs="$__UnprocessedBuildArgs $1"
+ ;;
+ esac
+
+ shift
+done
+
+if [ "$__BuildArch" == "armel" ]; then
+ __LLDB_Package="lldb-3.5-dev"
+fi
+__UbuntuPackages+=" ${__LLDB_Package:-}"
+
+if [ -z "$__RootfsDir" ] && [ ! -z "$ROOTFS_DIR" ]; then
+ __RootfsDir=$ROOTFS_DIR
+fi
+
+if [ -z "$__RootfsDir" ]; then
+ __RootfsDir="$__CrossDir/../../../.tools/rootfs/$__BuildArch"
+fi
+
+if [ -d "$__RootfsDir" ]; then
+ if [ $__SkipUnmount == 0 ]; then
+ umount $__RootfsDir/* || true
+ fi
+ rm -rf $__RootfsDir
+fi
+
+mkdir -p $__RootfsDir
+__RootfsDir="$( cd "$__RootfsDir" && pwd )"
+
+if [[ "$__CodeName" == "alpine" ]]; then
+ __ApkToolsVersion=2.9.1
+ __ApkToolsDir=$(mktemp -d)
+ wget https://github.com/alpinelinux/apk-tools/releases/download/v$__ApkToolsVersion/apk-tools-$__ApkToolsVersion-x86_64-linux.tar.gz -P $__ApkToolsDir
+ tar -xf $__ApkToolsDir/apk-tools-$__ApkToolsVersion-x86_64-linux.tar.gz -C $__ApkToolsDir
+ mkdir -p $__RootfsDir/usr/bin
+ cp -v /usr/bin/qemu-$__QEMUArch-static $__RootfsDir/usr/bin
+
+ $__ApkToolsDir/apk-tools-$__ApkToolsVersion/apk \
+ -X http://dl-cdn.alpinelinux.org/alpine/v$__AlpineVersion/main \
+ -X http://dl-cdn.alpinelinux.org/alpine/v$__AlpineVersion/community \
+ -U --allow-untrusted --root $__RootfsDir --arch $__AlpineArch --initdb \
+ add $__AlpinePackages
+
+ if [[ -n "$__AlpinePackagesEdgeMain" ]]; then
+ $__ApkToolsDir/apk-tools-$__ApkToolsVersion/apk \
+ -X http://dl-cdn.alpinelinux.org/alpine/edge/main \
+ -U --allow-untrusted --root $__RootfsDir --arch $__AlpineArch --initdb \
+ add $__AlpinePackagesEdgeMain
+ fi
+
+ if [[ -n "$__AlpinePackagesEdgeCommunity" ]]; then
+ $__ApkToolsDir/apk-tools-$__ApkToolsVersion/apk \
+ -X http://dl-cdn.alpinelinux.org/alpine/edge/community \
+ -U --allow-untrusted --root $__RootfsDir --arch $__AlpineArch --initdb \
+ add $__AlpinePackagesEdgeCommunity
+ fi
+
+ rm -r $__ApkToolsDir
+elif [[ "$__CodeName" == "freebsd" ]]; then
+ mkdir -p $__RootfsDir/usr/local/etc
+ wget -O - https://download.freebsd.org/ftp/releases/amd64/${__FreeBSDBase}/base.txz | tar -C $__RootfsDir -Jxf - ./lib ./usr/lib ./usr/libdata ./usr/include ./usr/share/keys ./etc ./bin/freebsd-version
+ # For now, ask for 11 ABI even on 12. This can be revisited later.
+ echo "ABI = \"FreeBSD:11:amd64\"; FINGERPRINTS = \"${__RootfsDir}/usr/share/keys\"; REPOS_DIR = [\"${__RootfsDir}/etc/pkg\"]; REPO_AUTOUPDATE = NO; RUN_SCRIPTS = NO;" > ${__RootfsDir}/usr/local/etc/pkg.conf
+ echo "FreeBSD: { url: "pkg+http://pkg.FreeBSD.org/\${ABI}/quarterly", mirror_type: \"srv\", signature_type: \"fingerprints\", fingerprints: \"${__RootfsDir}/usr/share/keys/pkg\", enabled: yes }" > ${__RootfsDir}/etc/pkg/FreeBSD.conf
+ mkdir -p $__RootfsDir/tmp
+ # get and build package manager
+ wget -O - https://github.com/freebsd/pkg/archive/${__FreeBSDPkg}.tar.gz | tar -C $__RootfsDir/tmp -zxf -
+ cd $__RootfsDir/tmp/pkg-${__FreeBSDPkg}
+ # needed for install to succeed
+ mkdir -p $__RootfsDir/host/etc
+ ./autogen.sh && ./configure --prefix=$__RootfsDir/host && make && make install
+ rm -rf $__RootfsDir/tmp/pkg-${__FreeBSDPkg}
+ # install packages we need.
+ INSTALL_AS_USER=$(whoami) $__RootfsDir/host/sbin/pkg -r $__RootfsDir -C $__RootfsDir/usr/local/etc/pkg.conf update
+ INSTALL_AS_USER=$(whoami) $__RootfsDir/host/sbin/pkg -r $__RootfsDir -C $__RootfsDir/usr/local/etc/pkg.conf install --yes $__FreeBSDPackages
+elif [[ "$__CodeName" == "illumos" ]]; then
+ mkdir "$__RootfsDir/tmp"
+ pushd "$__RootfsDir/tmp"
+ JOBS="$(getconf _NPROCESSORS_ONLN)"
+ echo "Downloading sysroot."
+ wget -O - https://github.com/illumos/sysroot/releases/download/20181213-de6af22ae73b-v1/illumos-sysroot-i386-20181213-de6af22ae73b-v1.tar.gz | tar -C "$__RootfsDir" -xzf -
+ echo "Building binutils. Please wait.."
+ wget -O - https://ftp.gnu.org/gnu/binutils/binutils-2.33.1.tar.bz2 | tar -xjf -
+ mkdir build-binutils && cd build-binutils
+ ../binutils-2.33.1/configure --prefix="$__RootfsDir" --target="x86_64-sun-solaris2.10" --program-prefix="x86_64-illumos-" --with-sysroot="$__RootfsDir"
+ make -j "$JOBS" && make install && cd ..
+ echo "Building gcc. Please wait.."
+ wget -O - https://ftp.gnu.org/gnu/gcc/gcc-8.4.0/gcc-8.4.0.tar.xz | tar -xJf -
+ CFLAGS="-fPIC"
+ CXXFLAGS="-fPIC"
+ CXXFLAGS_FOR_TARGET="-fPIC"
+ CFLAGS_FOR_TARGET="-fPIC"
+ export CFLAGS CXXFLAGS CXXFLAGS_FOR_TARGET CFLAGS_FOR_TARGET
+ mkdir build-gcc && cd build-gcc
+ ../gcc-8.4.0/configure --prefix="$__RootfsDir" --target="x86_64-sun-solaris2.10" --program-prefix="x86_64-illumos-" --with-sysroot="$__RootfsDir" --with-gnu-as \
+ --with-gnu-ld --disable-nls --disable-libgomp --disable-libquadmath --disable-libssp --disable-libvtv --disable-libcilkrts --disable-libada --disable-libsanitizer \
+ --disable-libquadmath-support --disable-shared --enable-tls
+ make -j "$JOBS" && make install && cd ..
+ BaseUrl=https://pkgsrc.joyent.com
+ if [[ "$__UseMirror" == 1 ]]; then
+ BaseUrl=http://pkgsrc.smartos.skylime.net
+ fi
+ BaseUrl="$BaseUrl"/packages/SmartOS/2020Q1/x86_64/All
+ echo "Downloading dependencies."
+ read -ra array <<<"$__IllumosPackages"
+ for package in "${array[@]}"; do
+ echo "Installing $package..."
+ wget "$BaseUrl"/"$package".tgz
+ ar -x "$package".tgz
+ tar --skip-old-files -xzf "$package".tmp.tgz -C "$__RootfsDir" 2>/dev/null
+ done
+ echo "Cleaning up temporary files."
+ popd
+ rm -rf "$__RootfsDir"/{tmp,+*}
+ mkdir -p "$__RootfsDir"/usr/include/net
+ mkdir -p "$__RootfsDir"/usr/include/netpacket
+ wget -P "$__RootfsDir"/usr/include/net https://raw.githubusercontent.com/illumos/illumos-gate/master/usr/src/uts/common/io/bpf/net/bpf.h
+ wget -P "$__RootfsDir"/usr/include/net https://raw.githubusercontent.com/illumos/illumos-gate/master/usr/src/uts/common/io/bpf/net/dlt.h
+ wget -P "$__RootfsDir"/usr/include/netpacket https://raw.githubusercontent.com/illumos/illumos-gate/master/usr/src/uts/common/inet/sockmods/netpacket/packet.h
+ wget -P "$__RootfsDir"/usr/include/sys https://raw.githubusercontent.com/illumos/illumos-gate/master/usr/src/uts/common/sys/sdt.h
+elif [[ -n $__CodeName ]]; then
+ qemu-debootstrap --arch $__UbuntuArch $__CodeName $__RootfsDir $__UbuntuRepo
+ cp $__CrossDir/$__BuildArch/sources.list.$__CodeName $__RootfsDir/etc/apt/sources.list
+ chroot $__RootfsDir apt-get update
+ chroot $__RootfsDir apt-get -f -y install
+ chroot $__RootfsDir apt-get -y install $__UbuntuPackages
+ chroot $__RootfsDir symlinks -cr /usr
+ chroot $__RootfsDir apt-get clean
+
+ if [ $__SkipUnmount == 0 ]; then
+ umount $__RootfsDir/* || true
+ fi
+
+ if [[ "$__BuildArch" == "arm" && "$__CodeName" == "trusty" ]]; then
+ pushd $__RootfsDir
+ patch -p1 < $__CrossDir/$__BuildArch/trusty.patch
+ patch -p1 < $__CrossDir/$__BuildArch/trusty-lttng-2.4.patch
+ popd
+ fi
+
+ if [[ "$__BuildArch" == "armel" && "$__CodeName" == "jessie" ]]; then
+ pushd $__RootfsDir
+ patch -p1 < $__CrossDir/$__BuildArch/armel.jessie.patch
+ popd
+ fi
+elif [[ "$__Tizen" == "tizen" ]]; then
+ ROOTFS_DIR=$__RootfsDir $__CrossDir/$__BuildArch/tizen-build-rootfs.sh
+else
+ echo "Unsupported target platform."
+ usage;
+ exit 1
+fi
diff --git a/eng/common/cross/s390x/sources.list.bionic b/eng/common/cross/s390x/sources.list.bionic
new file mode 100644
index 000000000..210955740
--- /dev/null
+++ b/eng/common/cross/s390x/sources.list.bionic
@@ -0,0 +1,11 @@
+deb http://ports.ubuntu.com/ubuntu-ports/ bionic main restricted universe
+deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic main restricted universe
+
+deb http://ports.ubuntu.com/ubuntu-ports/ bionic-updates main restricted universe
+deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic-updates main restricted universe
+
+deb http://ports.ubuntu.com/ubuntu-ports/ bionic-backports main restricted
+deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic-backports main restricted
+
+deb http://ports.ubuntu.com/ubuntu-ports/ bionic-security main restricted universe multiverse
+deb-src http://ports.ubuntu.com/ubuntu-ports/ bionic-security main restricted universe multiverse
diff --git a/eng/common/cross/toolchain.cmake b/eng/common/cross/toolchain.cmake
new file mode 100644
index 000000000..fc11001aa
--- /dev/null
+++ b/eng/common/cross/toolchain.cmake
@@ -0,0 +1,242 @@
+set(CROSS_ROOTFS $ENV{ROOTFS_DIR})
+
+set(TARGET_ARCH_NAME $ENV{TARGET_BUILD_ARCH})
+if(EXISTS ${CROSS_ROOTFS}/bin/freebsd-version)
+ set(CMAKE_SYSTEM_NAME FreeBSD)
+elseif(EXISTS ${CROSS_ROOTFS}/usr/platform/i86pc)
+ set(CMAKE_SYSTEM_NAME SunOS)
+ set(ILLUMOS 1)
+else()
+ set(CMAKE_SYSTEM_NAME Linux)
+endif()
+set(CMAKE_SYSTEM_VERSION 1)
+
+if(TARGET_ARCH_NAME STREQUAL "armel")
+ set(CMAKE_SYSTEM_PROCESSOR armv7l)
+ set(TOOLCHAIN "arm-linux-gnueabi")
+ if("$ENV{__DistroRid}" MATCHES "tizen.*")
+ set(TIZEN_TOOLCHAIN "armv7l-tizen-linux-gnueabi/9.2.0")
+ endif()
+elseif(TARGET_ARCH_NAME STREQUAL "arm")
+ set(CMAKE_SYSTEM_PROCESSOR armv7l)
+ if(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/armv7-alpine-linux-musleabihf)
+ set(TOOLCHAIN "armv7-alpine-linux-musleabihf")
+ elseif(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/armv6-alpine-linux-musleabihf)
+ set(TOOLCHAIN "armv6-alpine-linux-musleabihf")
+ else()
+ set(TOOLCHAIN "arm-linux-gnueabihf")
+ endif()
+elseif(TARGET_ARCH_NAME STREQUAL "arm64")
+ set(CMAKE_SYSTEM_PROCESSOR aarch64)
+ if(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/aarch64-alpine-linux-musl)
+ set(TOOLCHAIN "aarch64-alpine-linux-musl")
+ else()
+ set(TOOLCHAIN "aarch64-linux-gnu")
+ endif()
+ if("$ENV{__DistroRid}" MATCHES "tizen.*")
+ set(TIZEN_TOOLCHAIN "aarch64-tizen-linux-gnu/9.2.0")
+ endif()
+elseif(TARGET_ARCH_NAME STREQUAL "s390x")
+ set(CMAKE_SYSTEM_PROCESSOR s390x)
+ set(TOOLCHAIN "s390x-linux-gnu")
+elseif(TARGET_ARCH_NAME STREQUAL "x86")
+ set(CMAKE_SYSTEM_PROCESSOR i686)
+ set(TOOLCHAIN "i686-linux-gnu")
+elseif (CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
+ set(CMAKE_SYSTEM_PROCESSOR "x86_64")
+ set(triple "x86_64-unknown-freebsd11")
+elseif (ILLUMOS)
+ set(CMAKE_SYSTEM_PROCESSOR "x86_64")
+ set(TOOLCHAIN "x86_64-illumos")
+else()
+ message(FATAL_ERROR "Arch is ${TARGET_ARCH_NAME}. Only armel, arm, arm64, s390x and x86 are supported!")
+endif()
+
+if(DEFINED ENV{TOOLCHAIN})
+ set(TOOLCHAIN $ENV{TOOLCHAIN})
+endif()
+
+# Specify include paths
+if(DEFINED TIZEN_TOOLCHAIN)
+ if(TARGET_ARCH_NAME STREQUAL "armel")
+ include_directories(SYSTEM ${CROSS_ROOTFS}/usr/lib/gcc/${TIZEN_TOOLCHAIN}/include/c++/)
+ include_directories(SYSTEM ${CROSS_ROOTFS}/usr/lib/gcc/${TIZEN_TOOLCHAIN}/include/c++/armv7l-tizen-linux-gnueabi)
+ endif()
+ if(TARGET_ARCH_NAME STREQUAL "arm64")
+ include_directories(SYSTEM ${CROSS_ROOTFS}/usr/lib64/gcc/${TIZEN_TOOLCHAIN}/include/c++/)
+ include_directories(SYSTEM ${CROSS_ROOTFS}/usr/lib64/gcc/${TIZEN_TOOLCHAIN}/include/c++/aarch64-tizen-linux-gnu)
+ endif()
+endif()
+
+if("$ENV{__DistroRid}" MATCHES "android.*")
+ if(TARGET_ARCH_NAME STREQUAL "arm")
+ set(ANDROID_ABI armeabi-v7a)
+ elseif(TARGET_ARCH_NAME STREQUAL "arm64")
+ set(ANDROID_ABI arm64-v8a)
+ endif()
+
+ # extract platform number required by the NDK's toolchain
+ string(REGEX REPLACE ".*\\.([0-9]+)-.*" "\\1" ANDROID_PLATFORM "$ENV{__DistroRid}")
+
+ set(ANDROID_TOOLCHAIN clang)
+ set(FEATURE_EVENT_TRACE 0) # disable event trace as there is no lttng-ust package in termux repository
+ set(CMAKE_SYSTEM_LIBRARY_PATH "${CROSS_ROOTFS}/usr/lib")
+ set(CMAKE_SYSTEM_INCLUDE_PATH "${CROSS_ROOTFS}/usr/include")
+
+ # include official NDK toolchain script
+ include(${CROSS_ROOTFS}/../build/cmake/android.toolchain.cmake)
+elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
+ # we cross-compile by instructing clang
+ set(CMAKE_C_COMPILER_TARGET ${triple})
+ set(CMAKE_CXX_COMPILER_TARGET ${triple})
+ set(CMAKE_ASM_COMPILER_TARGET ${triple})
+ set(CMAKE_SYSROOT "${CROSS_ROOTFS}")
+elseif(ILLUMOS)
+ set(CMAKE_SYSROOT "${CROSS_ROOTFS}")
+
+ include_directories(SYSTEM ${CROSS_ROOTFS}/include)
+
+ set(TOOLSET_PREFIX ${TOOLCHAIN}-)
+ function(locate_toolchain_exec exec var)
+ string(TOUPPER ${exec} EXEC_UPPERCASE)
+ if(NOT "$ENV{CLR_${EXEC_UPPERCASE}}" STREQUAL "")
+ set(${var} "$ENV{CLR_${EXEC_UPPERCASE}}" PARENT_SCOPE)
+ return()
+ endif()
+
+ find_program(EXEC_LOCATION_${exec}
+ NAMES
+ "${TOOLSET_PREFIX}${exec}${CLR_CMAKE_COMPILER_FILE_NAME_VERSION}"
+ "${TOOLSET_PREFIX}${exec}")
+
+ if (EXEC_LOCATION_${exec} STREQUAL "EXEC_LOCATION_${exec}-NOTFOUND")
+ message(FATAL_ERROR "Unable to find toolchain executable. Name: ${exec}, Prefix: ${TOOLSET_PREFIX}.")
+ endif()
+ set(${var} ${EXEC_LOCATION_${exec}} PARENT_SCOPE)
+ endfunction()
+
+ set(CMAKE_SYSTEM_PREFIX_PATH "${CROSS_ROOTFS}")
+
+ locate_toolchain_exec(gcc CMAKE_C_COMPILER)
+ locate_toolchain_exec(g++ CMAKE_CXX_COMPILER)
+
+ set(CMAKE_C_STANDARD_LIBRARIES "${CMAKE_C_STANDARD_LIBRARIES} -lssp")
+ set(CMAKE_CXX_STANDARD_LIBRARIES "${CMAKE_CXX_STANDARD_LIBRARIES} -lssp")
+else()
+ set(CMAKE_SYSROOT "${CROSS_ROOTFS}")
+
+ set(CMAKE_C_COMPILER_EXTERNAL_TOOLCHAIN "${CROSS_ROOTFS}/usr")
+ set(CMAKE_CXX_COMPILER_EXTERNAL_TOOLCHAIN "${CROSS_ROOTFS}/usr")
+ set(CMAKE_ASM_COMPILER_EXTERNAL_TOOLCHAIN "${CROSS_ROOTFS}/usr")
+endif()
+
+# Specify link flags
+
+function(add_toolchain_linker_flag Flag)
+ set(Config "${ARGV1}")
+ set(CONFIG_SUFFIX "")
+ if (NOT Config STREQUAL "")
+ set(CONFIG_SUFFIX "_${Config}")
+ endif()
+ set("CMAKE_EXE_LINKER_FLAGS${CONFIG_SUFFIX}" "${CMAKE_EXE_LINKER_FLAGS${CONFIG_SUFFIX}} ${Flag}" PARENT_SCOPE)
+ set("CMAKE_SHARED_LINKER_FLAGS${CONFIG_SUFFIX}" "${CMAKE_SHARED_LINKER_FLAGS${CONFIG_SUFFIX}} ${Flag}" PARENT_SCOPE)
+endfunction()
+
+if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ add_toolchain_linker_flag("-Wl,--rpath-link=${CROSS_ROOTFS}/lib/${TOOLCHAIN}")
+ add_toolchain_linker_flag("-Wl,--rpath-link=${CROSS_ROOTFS}/usr/lib/${TOOLCHAIN}")
+endif()
+
+if(TARGET_ARCH_NAME STREQUAL "armel")
+ if(DEFINED TIZEN_TOOLCHAIN) # For Tizen only
+ add_toolchain_linker_flag("-B${CROSS_ROOTFS}/usr/lib/gcc/${TIZEN_TOOLCHAIN}")
+ add_toolchain_linker_flag("-L${CROSS_ROOTFS}/lib")
+ add_toolchain_linker_flag("-L${CROSS_ROOTFS}/usr/lib")
+ add_toolchain_linker_flag("-L${CROSS_ROOTFS}/usr/lib/gcc/${TIZEN_TOOLCHAIN}")
+ endif()
+elseif(TARGET_ARCH_NAME STREQUAL "arm64")
+ if(DEFINED TIZEN_TOOLCHAIN) # For Tizen only
+ add_toolchain_linker_flag("-B${CROSS_ROOTFS}/usr/lib64/gcc/${TIZEN_TOOLCHAIN}")
+ add_toolchain_linker_flag("-L${CROSS_ROOTFS}/lib64")
+ add_toolchain_linker_flag("-L${CROSS_ROOTFS}/usr/lib64")
+ add_toolchain_linker_flag("-L${CROSS_ROOTFS}/usr/lib64/gcc/${TIZEN_TOOLCHAIN}")
+
+ add_toolchain_linker_flag("-Wl,--rpath-link=${CROSS_ROOTFS}/lib64")
+ add_toolchain_linker_flag("-Wl,--rpath-link=${CROSS_ROOTFS}/usr/lib64")
+ add_toolchain_linker_flag("-Wl,--rpath-link=${CROSS_ROOTFS}/usr/lib64/gcc/${TIZEN_TOOLCHAIN}")
+ endif()
+elseif(TARGET_ARCH_NAME STREQUAL "x86")
+ add_toolchain_linker_flag(-m32)
+elseif(ILLUMOS)
+ add_toolchain_linker_flag("-L${CROSS_ROOTFS}/lib/amd64")
+ add_toolchain_linker_flag("-L${CROSS_ROOTFS}/usr/amd64/lib")
+endif()
+
+# Specify compile options
+
+if((TARGET_ARCH_NAME MATCHES "^(arm|armel|arm64|s390x)$" AND NOT "$ENV{__DistroRid}" MATCHES "android.*") OR ILLUMOS)
+ set(CMAKE_C_COMPILER_TARGET ${TOOLCHAIN})
+ set(CMAKE_CXX_COMPILER_TARGET ${TOOLCHAIN})
+ set(CMAKE_ASM_COMPILER_TARGET ${TOOLCHAIN})
+endif()
+
+if(TARGET_ARCH_NAME MATCHES "^(arm|armel)$")
+ add_compile_options(-mthumb)
+ if (NOT DEFINED CLR_ARM_FPU_TYPE)
+ set (CLR_ARM_FPU_TYPE vfpv3)
+ endif (NOT DEFINED CLR_ARM_FPU_TYPE)
+
+ add_compile_options (-mfpu=${CLR_ARM_FPU_TYPE})
+ if (NOT DEFINED CLR_ARM_FPU_CAPABILITY)
+ set (CLR_ARM_FPU_CAPABILITY 0x7)
+ endif (NOT DEFINED CLR_ARM_FPU_CAPABILITY)
+
+ add_definitions (-DCLR_ARM_FPU_CAPABILITY=${CLR_ARM_FPU_CAPABILITY})
+
+ if(TARGET_ARCH_NAME STREQUAL "armel")
+ add_compile_options(-mfloat-abi=softfp)
+ endif()
+elseif(TARGET_ARCH_NAME STREQUAL "x86")
+ add_compile_options(-m32)
+ add_compile_options(-Wno-error=unused-command-line-argument)
+endif()
+
+if(DEFINED TIZEN_TOOLCHAIN)
+ if(TARGET_ARCH_NAME MATCHES "^(armel|arm64)$")
+ add_compile_options(-Wno-deprecated-declarations) # compile-time option
+ add_compile_options(-D__extern_always_inline=inline) # compile-time option
+ endif()
+endif()
+
+# Set LLDB include and library paths for builds that need lldb.
+if(TARGET_ARCH_NAME MATCHES "^(arm|armel|x86)$")
+ if(TARGET_ARCH_NAME STREQUAL "x86")
+ set(LLVM_CROSS_DIR "$ENV{LLVM_CROSS_HOME}")
+ else() # arm/armel case
+ set(LLVM_CROSS_DIR "$ENV{LLVM_ARM_HOME}")
+ endif()
+ if(LLVM_CROSS_DIR)
+ set(WITH_LLDB_LIBS "${LLVM_CROSS_DIR}/lib/" CACHE STRING "")
+ set(WITH_LLDB_INCLUDES "${LLVM_CROSS_DIR}/include" CACHE STRING "")
+ set(LLDB_H "${WITH_LLDB_INCLUDES}" CACHE STRING "")
+ set(LLDB "${LLVM_CROSS_DIR}/lib/liblldb.so" CACHE STRING "")
+ else()
+ if(TARGET_ARCH_NAME STREQUAL "x86")
+ set(WITH_LLDB_LIBS "${CROSS_ROOTFS}/usr/lib/i386-linux-gnu" CACHE STRING "")
+ set(CHECK_LLVM_DIR "${CROSS_ROOTFS}/usr/lib/llvm-3.8/include")
+ if(EXISTS "${CHECK_LLVM_DIR}" AND IS_DIRECTORY "${CHECK_LLVM_DIR}")
+ set(WITH_LLDB_INCLUDES "${CHECK_LLVM_DIR}")
+ else()
+ set(WITH_LLDB_INCLUDES "${CROSS_ROOTFS}/usr/lib/llvm-3.6/include")
+ endif()
+ else() # arm/armel case
+ set(WITH_LLDB_LIBS "${CROSS_ROOTFS}/usr/lib/${TOOLCHAIN}" CACHE STRING "")
+ set(WITH_LLDB_INCLUDES "${CROSS_ROOTFS}/usr/lib/llvm-3.6/include" CACHE STRING "")
+ endif()
+ endif()
+endif()
+
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
diff --git a/eng/common/cross/x86/sources.list.bionic b/eng/common/cross/x86/sources.list.bionic
new file mode 100644
index 000000000..a71ccadcf
--- /dev/null
+++ b/eng/common/cross/x86/sources.list.bionic
@@ -0,0 +1,11 @@
+deb http://archive.ubuntu.com/ubuntu/ bionic main restricted universe
+deb-src http://archive.ubuntu.com/ubuntu/ bionic main restricted universe
+
+deb http://archive.ubuntu.com/ubuntu/ bionic-updates main restricted universe
+deb-src http://archive.ubuntu.com/ubuntu/ bionic-updates main restricted universe
+
+deb http://archive.ubuntu.com/ubuntu/ bionic-backports main restricted
+deb-src http://archive.ubuntu.com/ubuntu/ bionic-backports main restricted
+
+deb http://archive.ubuntu.com/ubuntu/ bionic-security main restricted universe multiverse
+deb-src http://archive.ubuntu.com/ubuntu/ bionic-security main restricted universe multiverse
diff --git a/eng/common/cross/x86/sources.list.trusty b/eng/common/cross/x86/sources.list.trusty
new file mode 100644
index 000000000..9b3085436
--- /dev/null
+++ b/eng/common/cross/x86/sources.list.trusty
@@ -0,0 +1,11 @@
+deb http://archive.ubuntu.com/ubuntu/ trusty main restricted universe
+deb-src http://archive.ubuntu.com/ubuntu/ trusty main restricted universe
+
+deb http://archive.ubuntu.com/ubuntu/ trusty-updates main restricted universe
+deb-src http://archive.ubuntu.com/ubuntu/ trusty-updates main restricted universe
+
+deb http://archive.ubuntu.com/ubuntu/ trusty-backports main restricted
+deb-src http://archive.ubuntu.com/ubuntu/ trusty-backports main restricted
+
+deb http://archive.ubuntu.com/ubuntu/ trusty-security main restricted universe multiverse
+deb-src http://archive.ubuntu.com/ubuntu/ trusty-security main restricted universe multiverse
diff --git a/eng/common/cross/x86/sources.list.xenial b/eng/common/cross/x86/sources.list.xenial
new file mode 100644
index 000000000..ad9c5a014
--- /dev/null
+++ b/eng/common/cross/x86/sources.list.xenial
@@ -0,0 +1,11 @@
+deb http://archive.ubuntu.com/ubuntu/ xenial main restricted universe
+deb-src http://archive.ubuntu.com/ubuntu/ xenial main restricted universe
+
+deb http://archive.ubuntu.com/ubuntu/ xenial-updates main restricted universe
+deb-src http://archive.ubuntu.com/ubuntu/ xenial-updates main restricted universe
+
+deb http://archive.ubuntu.com/ubuntu/ xenial-backports main restricted
+deb-src http://archive.ubuntu.com/ubuntu/ xenial-backports main restricted
+
+deb http://archive.ubuntu.com/ubuntu/ xenial-security main restricted universe multiverse
+deb-src http://archive.ubuntu.com/ubuntu/ xenial-security main restricted universe multiverse
diff --git a/eng/common/darc-init.ps1 b/eng/common/darc-init.ps1
new file mode 100644
index 000000000..435e76413
--- /dev/null
+++ b/eng/common/darc-init.ps1
@@ -0,0 +1,47 @@
+param (
+ $darcVersion = $null,
+ $versionEndpoint = 'https://maestro-prod.westus2.cloudapp.azure.com/api/assets/darc-version?api-version=2019-01-16',
+ $verbosity = 'minimal',
+ $toolpath = $null
+)
+
+. $PSScriptRoot\tools.ps1
+
+function InstallDarcCli ($darcVersion, $toolpath) {
+ $darcCliPackageName = 'microsoft.dotnet.darc'
+
+ $dotnetRoot = InitializeDotNetCli -install:$true
+ $dotnet = "$dotnetRoot\dotnet.exe"
+ $toolList = & "$dotnet" tool list -g
+
+ if ($toolList -like "*$darcCliPackageName*") {
+ & "$dotnet" tool uninstall $darcCliPackageName -g
+ }
+
+ # If the user didn't explicitly specify the darc version,
+ # query the Maestro API for the correct version of darc to install.
+ if (-not $darcVersion) {
+ $darcVersion = $(Invoke-WebRequest -Uri $versionEndpoint -UseBasicParsing).Content
+ }
+
+ $arcadeServicesSource = 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json'
+
+ Write-Host "Installing Darc CLI version $darcVersion..."
+ Write-Host 'You may need to restart your command window if this is the first dotnet tool you have installed.'
+ if (-not $toolpath) {
+ Write-Host "'$dotnet' tool install $darcCliPackageName --version $darcVersion --add-source '$arcadeServicesSource' -v $verbosity -g"
+ & "$dotnet" tool install $darcCliPackageName --version $darcVersion --add-source "$arcadeServicesSource" -v $verbosity -g
+ }else {
+ Write-Host "'$dotnet' tool install $darcCliPackageName --version $darcVersion --add-source '$arcadeServicesSource' -v $verbosity --tool-path '$toolpath'"
+ & "$dotnet" tool install $darcCliPackageName --version $darcVersion --add-source "$arcadeServicesSource" -v $verbosity --tool-path "$toolpath"
+ }
+}
+
+try {
+ InstallDarcCli $darcVersion $toolpath
+}
+catch {
+ Write-Host $_.ScriptStackTrace
+ Write-PipelineTelemetryError -Category 'Darc' -Message $_
+ ExitWithExitCode 1
+}
\ No newline at end of file
diff --git a/eng/common/darc-init.sh b/eng/common/darc-init.sh
new file mode 100644
index 000000000..39abdbecd
--- /dev/null
+++ b/eng/common/darc-init.sh
@@ -0,0 +1,82 @@
+#!/usr/bin/env bash
+
+source="${BASH_SOURCE[0]}"
+darcVersion=''
+versionEndpoint='https://maestro-prod.westus2.cloudapp.azure.com/api/assets/darc-version?api-version=2019-01-16'
+verbosity='minimal'
+
+while [[ $# > 0 ]]; do
+ opt="$(echo "$1" | tr "[:upper:]" "[:lower:]")"
+ case "$opt" in
+ --darcversion)
+ darcVersion=$2
+ shift
+ ;;
+ --versionendpoint)
+ versionEndpoint=$2
+ shift
+ ;;
+ --verbosity)
+ verbosity=$2
+ shift
+ ;;
+ --toolpath)
+ toolpath=$2
+ shift
+ ;;
+ *)
+ echo "Invalid argument: $1"
+ usage
+ exit 1
+ ;;
+ esac
+
+ shift
+done
+
+# resolve $source until the file is no longer a symlink
+while [[ -h "$source" ]]; do
+ scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+ source="$(readlink "$source")"
+ # if $source was a relative symlink, we need to resolve it relative to the path where the
+ # symlink file was located
+ [[ $source != /* ]] && source="$scriptroot/$source"
+done
+scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+
+. "$scriptroot/tools.sh"
+
+if [ -z "$darcVersion" ]; then
+ darcVersion=$(curl -X GET "$versionEndpoint" -H "accept: text/plain")
+fi
+
+function InstallDarcCli {
+ local darc_cli_package_name="microsoft.dotnet.darc"
+
+ InitializeDotNetCli
+ local dotnet_root=$_InitializeDotNetCli
+
+ if [ -z "$toolpath" ]; then
+ local tool_list=$($dotnet_root/dotnet tool list -g)
+ if [[ $tool_list = *$darc_cli_package_name* ]]; then
+ echo $($dotnet_root/dotnet tool uninstall $darc_cli_package_name -g)
+ fi
+ else
+ local tool_list=$($dotnet_root/dotnet tool list --tool-path "$toolpath")
+ if [[ $tool_list = *$darc_cli_package_name* ]]; then
+ echo $($dotnet_root/dotnet tool uninstall $darc_cli_package_name --tool-path "$toolpath")
+ fi
+ fi
+
+ local arcadeServicesSource="https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json"
+
+ echo "Installing Darc CLI version $darcVersion..."
+ echo "You may need to restart your command shell if this is the first dotnet tool you have installed."
+ if [ -z "$toolpath" ]; then
+ echo $($dotnet_root/dotnet tool install $darc_cli_package_name --version $darcVersion --add-source "$arcadeServicesSource" -v $verbosity -g)
+ else
+ echo $($dotnet_root/dotnet tool install $darc_cli_package_name --version $darcVersion --add-source "$arcadeServicesSource" -v $verbosity --tool-path "$toolpath")
+ fi
+}
+
+InstallDarcCli
diff --git a/eng/common/dotnet-install.cmd b/eng/common/dotnet-install.cmd
new file mode 100644
index 000000000..b1c2642e7
--- /dev/null
+++ b/eng/common/dotnet-install.cmd
@@ -0,0 +1,2 @@
+@echo off
+powershell -ExecutionPolicy ByPass -NoProfile -command "& """%~dp0dotnet-install.ps1""" %*"
\ No newline at end of file
diff --git a/eng/common/dotnet-install.ps1 b/eng/common/dotnet-install.ps1
new file mode 100644
index 000000000..811f0f717
--- /dev/null
+++ b/eng/common/dotnet-install.ps1
@@ -0,0 +1,28 @@
+[CmdletBinding(PositionalBinding=$false)]
+Param(
+ [string] $verbosity = 'minimal',
+ [string] $architecture = '',
+ [string] $version = 'Latest',
+ [string] $runtime = 'dotnet',
+ [string] $RuntimeSourceFeed = '',
+ [string] $RuntimeSourceFeedKey = ''
+)
+
+. $PSScriptRoot\tools.ps1
+
+$dotnetRoot = Join-Path $RepoRoot '.dotnet'
+
+$installdir = $dotnetRoot
+try {
+ if ($architecture -and $architecture.Trim() -eq 'x86') {
+ $installdir = Join-Path $installdir 'x86'
+ }
+ InstallDotNet $installdir $version $architecture $runtime $true -RuntimeSourceFeed $RuntimeSourceFeed -RuntimeSourceFeedKey $RuntimeSourceFeedKey
+}
+catch {
+ Write-Host $_.ScriptStackTrace
+ Write-PipelineTelemetryError -Category 'InitializeToolset' -Message $_
+ ExitWithExitCode 1
+}
+
+ExitWithExitCode 0
diff --git a/eng/common/dotnet-install.sh b/eng/common/dotnet-install.sh
new file mode 100644
index 000000000..fdfeea66e
--- /dev/null
+++ b/eng/common/dotnet-install.sh
@@ -0,0 +1,84 @@
+#!/usr/bin/env bash
+
+source="${BASH_SOURCE[0]}"
+# resolve $source until the file is no longer a symlink
+while [[ -h "$source" ]]; do
+ scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+ source="$(readlink "$source")"
+ # if $source was a relative symlink, we need to resolve it relative to the path where the
+ # symlink file was located
+ [[ $source != /* ]] && source="$scriptroot/$source"
+done
+scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+
+. "$scriptroot/tools.sh"
+
+version='Latest'
+architecture=''
+runtime='dotnet'
+runtimeSourceFeed=''
+runtimeSourceFeedKey=''
+while [[ $# > 0 ]]; do
+ opt="$(echo "$1" | tr "[:upper:]" "[:lower:]")"
+ case "$opt" in
+ -version|-v)
+ shift
+ version="$1"
+ ;;
+ -architecture|-a)
+ shift
+ architecture="$1"
+ ;;
+ -runtime|-r)
+ shift
+ runtime="$1"
+ ;;
+ -runtimesourcefeed)
+ shift
+ runtimeSourceFeed="$1"
+ ;;
+ -runtimesourcefeedkey)
+ shift
+ runtimeSourceFeedKey="$1"
+ ;;
+ *)
+ Write-PipelineTelemetryError -Category 'Build' -Message "Invalid argument: $1"
+ exit 1
+ ;;
+ esac
+ shift
+done
+
+# Use uname to determine what the CPU is, see https://en.wikipedia.org/wiki/Uname#Examples
+cpuname=$(uname -m)
+case $cpuname in
+ aarch64)
+ buildarch=arm64
+ ;;
+ amd64|x86_64)
+ buildarch=x64
+ ;;
+ armv*l)
+ buildarch=arm
+ ;;
+ i686)
+ buildarch=x86
+ ;;
+ *)
+ echo "Unknown CPU $cpuname detected, treating it as x64"
+ buildarch=x64
+ ;;
+esac
+
+dotnetRoot="${repo_root}.dotnet"
+if [[ $architecture != "" ]] && [[ $architecture != $buildarch ]]; then
+ dotnetRoot="$dotnetRoot/$architecture"
+fi
+
+InstallDotNet $dotnetRoot $version "$architecture" $runtime true $runtimeSourceFeed $runtimeSourceFeedKey || {
+ local exit_code=$?
+ Write-PipelineTelemetryError -Category 'InitializeToolset' -Message "dotnet-install.sh failed (exit code '$exit_code')." >&2
+ ExitWithExitCode $exit_code
+}
+
+ExitWithExitCode 0
diff --git a/eng/common/enable-cross-org-publishing.ps1 b/eng/common/enable-cross-org-publishing.ps1
new file mode 100644
index 000000000..da09da4f1
--- /dev/null
+++ b/eng/common/enable-cross-org-publishing.ps1
@@ -0,0 +1,13 @@
+param(
+ [string] $token
+)
+
+
+. $PSScriptRoot\pipeline-logging-functions.ps1
+
+# Write-PipelineSetVariable will no-op if a variable named $ci is not defined
+# Since this script is only ever called in AzDO builds, just universally set it
+$ci = $true
+
+Write-PipelineSetVariable -Name 'VSS_NUGET_ACCESSTOKEN' -Value $token -IsMultiJobVariable $false
+Write-PipelineSetVariable -Name 'VSS_NUGET_URI_PREFIXES' -Value 'https://dnceng.pkgs.visualstudio.com/;https://pkgs.dev.azure.com/dnceng/;https://devdiv.pkgs.visualstudio.com/;https://pkgs.dev.azure.com/devdiv/' -IsMultiJobVariable $false
diff --git a/eng/common/generate-graph-files.ps1 b/eng/common/generate-graph-files.ps1
new file mode 100644
index 000000000..0728b1a8b
--- /dev/null
+++ b/eng/common/generate-graph-files.ps1
@@ -0,0 +1,86 @@
+Param(
+ [Parameter(Mandatory=$true)][string] $barToken, # Token generated at https://maestro-prod.westus2.cloudapp.azure.com/Account/Tokens
+ [Parameter(Mandatory=$true)][string] $gitHubPat, # GitHub personal access token from https://github.com/settings/tokens (no auth scopes needed)
+ [Parameter(Mandatory=$true)][string] $azdoPat, # Azure Dev Ops tokens from https://dev.azure.com/dnceng/_details/security/tokens (code read scope needed)
+ [Parameter(Mandatory=$true)][string] $outputFolder, # Where the graphviz.txt file will be created
+ [string] $darcVersion, # darc's version
+ [string] $graphvizVersion = '2.38', # GraphViz version
+ [switch] $includeToolset # Whether the graph should include toolset dependencies or not. i.e. arcade, optimization. For more about
+ # toolset dependencies see https://github.com/dotnet/arcade/blob/master/Documentation/Darc.md#toolset-vs-product-dependencies
+)
+
+function CheckExitCode ([string]$stage)
+{
+ $exitCode = $LASTEXITCODE
+ if ($exitCode -ne 0) {
+ Write-PipelineTelemetryError -Category 'Arcade' -Message "Something failed in stage: '$stage'. Check for errors above. Exiting now..."
+ ExitWithExitCode $exitCode
+ }
+}
+
+try {
+ $ErrorActionPreference = 'Stop'
+ . $PSScriptRoot\tools.ps1
+
+ Import-Module -Name (Join-Path $PSScriptRoot 'native\CommonLibrary.psm1')
+
+ Push-Location $PSScriptRoot
+
+ Write-Host 'Installing darc...'
+ . .\darc-init.ps1 -darcVersion $darcVersion
+ CheckExitCode 'Running darc-init'
+
+ $engCommonBaseDir = Join-Path $PSScriptRoot 'native\'
+ $graphvizInstallDir = CommonLibrary\Get-NativeInstallDirectory
+ $nativeToolBaseUri = 'https://netcorenativeassets.blob.core.windows.net/resource-packages/external'
+ $installBin = Join-Path $graphvizInstallDir 'bin'
+
+ Write-Host 'Installing dot...'
+ .\native\install-tool.ps1 -ToolName graphviz -InstallPath $installBin -BaseUri $nativeToolBaseUri -CommonLibraryDirectory $engCommonBaseDir -Version $graphvizVersion -Verbose
+
+ $darcExe = "$env:USERPROFILE\.dotnet\tools"
+ $darcExe = Resolve-Path "$darcExe\darc.exe"
+
+ Create-Directory $outputFolder
+
+ # Generate 3 graph descriptions:
+ # 1. Flat with coherency information
+ # 2. Graphviz (dot) file
+ # 3. Standard dependency graph
+ $graphVizFilePath = "$outputFolder\graphviz.txt"
+ $graphVizImageFilePath = "$outputFolder\graph.png"
+ $normalGraphFilePath = "$outputFolder\graph-full.txt"
+ $flatGraphFilePath = "$outputFolder\graph-flat.txt"
+ $baseOptions = @( '--github-pat', "$gitHubPat", '--azdev-pat', "$azdoPat", '--password', "$barToken" )
+
+ if ($includeToolset) {
+ Write-Host 'Toolsets will be included in the graph...'
+ $baseOptions += @( '--include-toolset' )
+ }
+
+ Write-Host 'Generating standard dependency graph...'
+ & "$darcExe" get-dependency-graph @baseOptions --output-file $normalGraphFilePath
+ CheckExitCode 'Generating normal dependency graph'
+
+ Write-Host 'Generating flat dependency graph and graphviz file...'
+ & "$darcExe" get-dependency-graph @baseOptions --flat --coherency --graphviz $graphVizFilePath --output-file $flatGraphFilePath
+ CheckExitCode 'Generating flat and graphviz dependency graph'
+
+ Write-Host "Generating graph image $graphVizFilePath"
+ $dotFilePath = Join-Path $installBin "graphviz\$graphvizVersion\release\bin\dot.exe"
+ & "$dotFilePath" -Tpng -o"$graphVizImageFilePath" "$graphVizFilePath"
+ CheckExitCode 'Generating graphviz image'
+
+ Write-Host "'$graphVizFilePath', '$flatGraphFilePath', '$normalGraphFilePath' and '$graphVizImageFilePath' created!"
+}
+catch {
+ if (!$includeToolset) {
+ Write-Host 'This might be a toolset repo which includes only toolset dependencies. ' -NoNewline -ForegroundColor Yellow
+ Write-Host 'Since -includeToolset is not set there is no graph to create. Include -includeToolset and try again...' -ForegroundColor Yellow
+ }
+ Write-Host $_.ScriptStackTrace
+ Write-PipelineTelemetryError -Category 'Arcade' -Message $_
+ ExitWithExitCode 1
+} finally {
+ Pop-Location
+}
\ No newline at end of file
diff --git a/eng/common/generate-locproject.ps1 b/eng/common/generate-locproject.ps1
new file mode 100644
index 000000000..25e97ac00
--- /dev/null
+++ b/eng/common/generate-locproject.ps1
@@ -0,0 +1,117 @@
+Param(
+ [Parameter(Mandatory=$true)][string] $SourcesDirectory, # Directory where source files live; if using a Localize directory it should live in here
+ [string] $LanguageSet = 'VS_Main_Languages', # Language set to be used in the LocProject.json
+ [switch] $UseCheckedInLocProjectJson, # When set, generates a LocProject.json and compares it to one that already exists in the repo; otherwise just generates one
+ [switch] $CreateNeutralXlfs # Creates neutral xlf files. Only set to false when running locally
+)
+
+# Generates LocProject.json files for the OneLocBuild task. OneLocBuildTask is described here:
+# https://ceapex.visualstudio.com/CEINTL/_wiki/wikis/CEINTL.wiki/107/Localization-with-OneLocBuild-Task
+
+Set-StrictMode -Version 2.0
+$ErrorActionPreference = "Stop"
+. $PSScriptRoot\tools.ps1
+
+Import-Module -Name (Join-Path $PSScriptRoot 'native\CommonLibrary.psm1')
+
+$exclusionsFilePath = "$SourcesDirectory\eng\Localize\LocExclusions.json"
+$exclusions = @{ Exclusions = @() }
+if (Test-Path -Path $exclusionsFilePath)
+{
+ $exclusions = Get-Content "$exclusionsFilePath" | ConvertFrom-Json
+}
+
+Push-Location "$SourcesDirectory" # push location for Resolve-Path -Relative to work
+
+# Template files
+$jsonFiles = @()
+$jsonTemplateFiles = Get-ChildItem -Recurse -Path "$SourcesDirectory" | Where-Object { $_.FullName -Match "\.template\.config\\localize\\.+\.en\.json" } # .NET templating pattern
+$jsonTemplateFiles | ForEach-Object {
+ $null = $_.Name -Match "(.+)\.[\w-]+\.json" # matches '[filename].[langcode].json
+
+ $destinationFile = "$($_.Directory.FullName)\$($Matches.1).json"
+ $jsonFiles += Copy-Item "$($_.FullName)" -Destination $destinationFile -PassThru
+}
+
+$jsonWinformsTemplateFiles = Get-ChildItem -Recurse -Path "$SourcesDirectory" | Where-Object { $_.FullName -Match "en\\strings\.json" } # current winforms pattern
+
+$xlfFiles = @()
+
+$allXlfFiles = Get-ChildItem -Recurse -Path "$SourcesDirectory\*\*.xlf"
+$langXlfFiles = @()
+if ($allXlfFiles) {
+ $null = $allXlfFiles[0].FullName -Match "\.([\w-]+)\.xlf" # matches '[langcode].xlf'
+ $firstLangCode = $Matches.1
+ $langXlfFiles = Get-ChildItem -Recurse -Path "$SourcesDirectory\*\*.$firstLangCode.xlf"
+}
+$langXlfFiles | ForEach-Object {
+ $null = $_.Name -Match "(.+)\.[\w-]+\.xlf" # matches '[filename].[langcode].xlf
+
+ $destinationFile = "$($_.Directory.FullName)\$($Matches.1).xlf"
+ $xlfFiles += Copy-Item "$($_.FullName)" -Destination $destinationFile -PassThru
+}
+
+$locFiles = $jsonFiles + $jsonWinformsTemplateFiles + $xlfFiles
+
+$locJson = @{
+ Projects = @(
+ @{
+ LanguageSet = $LanguageSet
+ LocItems = @(
+ $locFiles | ForEach-Object {
+ $outputPath = "$(($_.DirectoryName | Resolve-Path -Relative) + "\")"
+ $continue = $true
+ foreach ($exclusion in $exclusions.Exclusions) {
+ if ($outputPath.Contains($exclusion))
+ {
+ $continue = $false
+ }
+ }
+ $sourceFile = ($_.FullName | Resolve-Path -Relative)
+ if (!$CreateNeutralXlfs -and $_.Extension -eq '.xlf') {
+ Remove-Item -Path $sourceFile
+ }
+ if ($continue)
+ {
+ if ($_.Directory.Name -eq 'en' -and $_.Extension -eq '.json') {
+ return @{
+ SourceFile = $sourceFile
+ CopyOption = "LangIDOnPath"
+ OutputPath = "$($_.Directory.Parent.FullName | Resolve-Path -Relative)\"
+ }
+ }
+ else {
+ return @{
+ SourceFile = $sourceFile
+ CopyOption = "LangIDOnName"
+ OutputPath = $outputPath
+ }
+ }
+ }
+ }
+ )
+ }
+ )
+}
+
+$json = ConvertTo-Json $locJson -Depth 5
+Write-Host "LocProject.json generated:`n`n$json`n`n"
+Pop-Location
+
+if (!$UseCheckedInLocProjectJson) {
+ New-Item "$SourcesDirectory\eng\Localize\LocProject.json" -Force # Need this to make sure the Localize directory is created
+ Set-Content "$SourcesDirectory\eng\Localize\LocProject.json" $json
+}
+else {
+ New-Item "$SourcesDirectory\eng\Localize\LocProject-generated.json" -Force # Need this to make sure the Localize directory is created
+ Set-Content "$SourcesDirectory\eng\Localize\LocProject-generated.json" $json
+
+ if ((Get-FileHash "$SourcesDirectory\eng\Localize\LocProject-generated.json").Hash -ne (Get-FileHash "$SourcesDirectory\eng\Localize\LocProject.json").Hash) {
+ Write-PipelineTelemetryError -Category "OneLocBuild" -Message "Existing LocProject.json differs from generated LocProject.json. Download LocProject-generated.json and compare them."
+
+ exit 1
+ }
+ else {
+ Write-Host "Generated LocProject.json and current LocProject.json are identical."
+ }
+}
\ No newline at end of file
diff --git a/eng/common/helixpublish.proj b/eng/common/helixpublish.proj
new file mode 100644
index 000000000..d7f185856
--- /dev/null
+++ b/eng/common/helixpublish.proj
@@ -0,0 +1,26 @@
+
+
+
+ msbuild
+
+
+
+
+ %(Identity)
+
+
+
+
+
+ $(WorkItemDirectory)
+ $(WorkItemCommand)
+ $(WorkItemTimeout)
+
+
+
+
+
+
+
+
+
diff --git a/eng/common/init-tools-native.cmd b/eng/common/init-tools-native.cmd
new file mode 100644
index 000000000..438cd548c
--- /dev/null
+++ b/eng/common/init-tools-native.cmd
@@ -0,0 +1,3 @@
+@echo off
+powershell -NoProfile -NoLogo -ExecutionPolicy ByPass -command "& """%~dp0init-tools-native.ps1""" %*"
+exit /b %ErrorLevel%
\ No newline at end of file
diff --git a/eng/common/init-tools-native.ps1 b/eng/common/init-tools-native.ps1
new file mode 100644
index 000000000..db830c00a
--- /dev/null
+++ b/eng/common/init-tools-native.ps1
@@ -0,0 +1,152 @@
+<#
+.SYNOPSIS
+Entry point script for installing native tools
+
+.DESCRIPTION
+Reads $RepoRoot\global.json file to determine native assets to install
+and executes installers for those tools
+
+.PARAMETER BaseUri
+Base file directory or Url from which to acquire tool archives
+
+.PARAMETER InstallDirectory
+Directory to install native toolset. This is a command-line override for the default
+Install directory precedence order:
+- InstallDirectory command-line override
+- NETCOREENG_INSTALL_DIRECTORY environment variable
+- (default) %USERPROFILE%/.netcoreeng/native
+
+.PARAMETER Clean
+Switch specifying to not install anything, but cleanup native asset folders
+
+.PARAMETER Force
+Clean and then install tools
+
+.PARAMETER DownloadRetries
+Total number of retry attempts
+
+.PARAMETER RetryWaitTimeInSeconds
+Wait time between retry attempts in seconds
+
+.PARAMETER GlobalJsonFile
+File path to global.json file
+
+.NOTES
+#>
+[CmdletBinding(PositionalBinding=$false)]
+Param (
+ [string] $BaseUri = 'https://netcorenativeassets.blob.core.windows.net/resource-packages/external',
+ [string] $InstallDirectory,
+ [switch] $Clean = $False,
+ [switch] $Force = $False,
+ [int] $DownloadRetries = 5,
+ [int] $RetryWaitTimeInSeconds = 30,
+ [string] $GlobalJsonFile
+)
+
+if (!$GlobalJsonFile) {
+ $GlobalJsonFile = Join-Path (Get-Item $PSScriptRoot).Parent.Parent.FullName 'global.json'
+}
+
+Set-StrictMode -version 2.0
+$ErrorActionPreference='Stop'
+
+. $PSScriptRoot\pipeline-logging-functions.ps1
+Import-Module -Name (Join-Path $PSScriptRoot 'native\CommonLibrary.psm1')
+
+try {
+ # Define verbose switch if undefined
+ $Verbose = $VerbosePreference -Eq 'Continue'
+
+ $EngCommonBaseDir = Join-Path $PSScriptRoot 'native\'
+ $NativeBaseDir = $InstallDirectory
+ if (!$NativeBaseDir) {
+ $NativeBaseDir = CommonLibrary\Get-NativeInstallDirectory
+ }
+ $Env:CommonLibrary_NativeInstallDir = $NativeBaseDir
+ $InstallBin = Join-Path $NativeBaseDir 'bin'
+ $InstallerPath = Join-Path $EngCommonBaseDir 'install-tool.ps1'
+
+ # Process tools list
+ Write-Host "Processing $GlobalJsonFile"
+ If (-Not (Test-Path $GlobalJsonFile)) {
+ Write-Host "Unable to find '$GlobalJsonFile'"
+ exit 0
+ }
+ $NativeTools = Get-Content($GlobalJsonFile) -Raw |
+ ConvertFrom-Json |
+ Select-Object -Expand 'native-tools' -ErrorAction SilentlyContinue
+ if ($NativeTools) {
+ $NativeTools.PSObject.Properties | ForEach-Object {
+ $ToolName = $_.Name
+ $ToolVersion = $_.Value
+ $LocalInstallerArguments = @{ ToolName = "$ToolName" }
+ $LocalInstallerArguments += @{ InstallPath = "$InstallBin" }
+ $LocalInstallerArguments += @{ BaseUri = "$BaseUri" }
+ $LocalInstallerArguments += @{ CommonLibraryDirectory = "$EngCommonBaseDir" }
+ $LocalInstallerArguments += @{ Version = "$ToolVersion" }
+
+ if ($Verbose) {
+ $LocalInstallerArguments += @{ Verbose = $True }
+ }
+ if (Get-Variable 'Force' -ErrorAction 'SilentlyContinue') {
+ if($Force) {
+ $LocalInstallerArguments += @{ Force = $True }
+ }
+ }
+ if ($Clean) {
+ $LocalInstallerArguments += @{ Clean = $True }
+ }
+
+ Write-Verbose "Installing $ToolName version $ToolVersion"
+ Write-Verbose "Executing '$InstallerPath $($LocalInstallerArguments.Keys.ForEach({"-$_ '$($LocalInstallerArguments.$_)'"}) -join ' ')'"
+ & $InstallerPath @LocalInstallerArguments
+ if ($LASTEXITCODE -Ne "0") {
+ $errMsg = "$ToolName installation failed"
+ if ((Get-Variable 'DoNotAbortNativeToolsInstallationOnFailure' -ErrorAction 'SilentlyContinue') -and $DoNotAbortNativeToolsInstallationOnFailure) {
+ $showNativeToolsWarning = $true
+ if ((Get-Variable 'DoNotDisplayNativeToolsInstallationWarnings' -ErrorAction 'SilentlyContinue') -and $DoNotDisplayNativeToolsInstallationWarnings) {
+ $showNativeToolsWarning = $false
+ }
+ if ($showNativeToolsWarning) {
+ Write-Warning $errMsg
+ }
+ $toolInstallationFailure = $true
+ } else {
+ # We cannot change this to Write-PipelineTelemetryError because of https://github.com/dotnet/arcade/issues/4482
+ Write-Host $errMsg
+ exit 1
+ }
+ }
+ }
+
+ if ((Get-Variable 'toolInstallationFailure' -ErrorAction 'SilentlyContinue') -and $toolInstallationFailure) {
+ # We cannot change this to Write-PipelineTelemetryError because of https://github.com/dotnet/arcade/issues/4482
+ Write-Host 'Native tools bootstrap failed'
+ exit 1
+ }
+ }
+ else {
+ Write-Host 'No native tools defined in global.json'
+ exit 0
+ }
+
+ if ($Clean) {
+ exit 0
+ }
+ if (Test-Path $InstallBin) {
+ Write-Host 'Native tools are available from ' (Convert-Path -Path $InstallBin)
+ Write-Host "##vso[task.prependpath]$(Convert-Path -Path $InstallBin)"
+ return $InstallBin
+ }
+ else {
+ Write-PipelineTelemetryError -Category 'NativeToolsBootstrap' -Message 'Native tools install directory does not exist, installation failed'
+ exit 1
+ }
+ exit 0
+}
+catch {
+ Write-Host $_.ScriptStackTrace
+ Write-PipelineTelemetryError -Category 'NativeToolsBootstrap' -Message $_
+ ExitWithExitCode 1
+}
diff --git a/eng/common/init-tools-native.sh b/eng/common/init-tools-native.sh
new file mode 100644
index 000000000..5bd205b5d
--- /dev/null
+++ b/eng/common/init-tools-native.sh
@@ -0,0 +1,238 @@
+#!/usr/bin/env bash
+
+source="${BASH_SOURCE[0]}"
+scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+
+base_uri='https://netcorenativeassets.blob.core.windows.net/resource-packages/external'
+install_directory=''
+clean=false
+force=false
+download_retries=5
+retry_wait_time_seconds=30
+global_json_file="$(dirname "$(dirname "${scriptroot}")")/global.json"
+declare -A native_assets
+
+. $scriptroot/pipeline-logging-functions.sh
+. $scriptroot/native/common-library.sh
+
+while (($# > 0)); do
+ lowerI="$(echo $1 | tr "[:upper:]" "[:lower:]")"
+ case $lowerI in
+ --baseuri)
+ base_uri=$2
+ shift 2
+ ;;
+ --installdirectory)
+ install_directory=$2
+ shift 2
+ ;;
+ --clean)
+ clean=true
+ shift 1
+ ;;
+ --force)
+ force=true
+ shift 1
+ ;;
+ --donotabortonfailure)
+ donotabortonfailure=true
+ shift 1
+ ;;
+ --donotdisplaywarnings)
+ donotdisplaywarnings=true
+ shift 1
+ ;;
+ --downloadretries)
+ download_retries=$2
+ shift 2
+ ;;
+ --retrywaittimeseconds)
+ retry_wait_time_seconds=$2
+ shift 2
+ ;;
+ --help)
+ echo "Common settings:"
+ echo " --installdirectory Directory to install native toolset."
+ echo " This is a command-line override for the default"
+ echo " Install directory precedence order:"
+ echo " - InstallDirectory command-line override"
+ echo " - NETCOREENG_INSTALL_DIRECTORY environment variable"
+ echo " - (default) %USERPROFILE%/.netcoreeng/native"
+ echo ""
+ echo " --clean Switch specifying not to install anything, but cleanup native asset folders"
+ echo " --donotabortonfailure Switch specifiying whether to abort native tools installation on failure"
+ echo " --donotdisplaywarnings Switch specifiying whether to display warnings during native tools installation on failure"
+ echo " --force Clean and then install tools"
+ echo " --help Print help and exit"
+ echo ""
+ echo "Advanced settings:"
+ echo " --baseuri Base URI for where to download native tools from"
+ echo " --downloadretries Number of times a download should be attempted"
+ echo " --retrywaittimeseconds Wait time between download attempts"
+ echo ""
+ exit 0
+ ;;
+ esac
+done
+
+function ReadGlobalJsonNativeTools {
+ # happy path: we have a proper JSON parsing tool `jq(1)` in PATH!
+ if command -v jq &> /dev/null; then
+
+ # jq: read each key/value pair under "native-tools" entry and emit:
+ # KEY="" VALUE=""
+ # followed by a null byte.
+ #
+ # bash: read line with null byte delimeter and push to array (for later `eval`uation).
+
+ while IFS= read -rd '' line; do
+ native_assets+=("$line")
+ done < <(jq -r '. |
+ select(has("native-tools")) |
+ ."native-tools" |
+ keys[] as $k |
+ @sh "KEY=\($k) VALUE=\(.[$k])\u0000"' "$global_json_file")
+
+ return
+ fi
+
+ # Warning: falling back to manually parsing JSON, which is not recommended.
+
+ # Following routine matches the output and escaping logic of jq(1)'s @sh formatter used above.
+ # It has been tested with several weird strings with escaped characters in entries (key and value)
+ # and results were compared with the output of jq(1) in binary representation using xxd(1);
+ # just before the assignment to 'native_assets' array (above and below).
+
+ # try to capture the section under "native-tools".
+ if [[ ! "$(cat "$global_json_file")" =~ \"native-tools\"[[:space:]\:\{]*([^\}]+) ]]; then
+ return
+ fi
+
+ section="${BASH_REMATCH[1]}"
+
+ parseStarted=0
+ possibleEnd=0
+ escaping=0
+ escaped=0
+ isKey=1
+
+ for (( i=0; i<${#section}; i++ )); do
+ char="${section:$i:1}"
+ if ! ((parseStarted)) && [[ "$char" =~ [[:space:],:] ]]; then continue; fi
+
+ if ! ((escaping)) && [[ "$char" == "\\" ]]; then
+ escaping=1
+ elif ((escaping)) && ! ((escaped)); then
+ escaped=1
+ fi
+
+ if ! ((parseStarted)) && [[ "$char" == "\"" ]]; then
+ parseStarted=1
+ possibleEnd=0
+ elif [[ "$char" == "'" ]]; then
+ token="$token'\\\''"
+ possibleEnd=0
+ elif ((escaping)) || [[ "$char" != "\"" ]]; then
+ token="$token$char"
+ possibleEnd=1
+ fi
+
+ if ((possibleEnd)) && ! ((escaping)) && [[ "$char" == "\"" ]]; then
+ # Use printf to unescape token to match jq(1)'s @sh formatting rules.
+ # do not use 'token="$(printf "$token")"' syntax, as $() eats the trailing linefeed.
+ printf -v token "'$token'"
+
+ if ((isKey)); then
+ KEY="$token"
+ isKey=0
+ else
+ line="KEY=$KEY VALUE=$token"
+ native_assets+=("$line")
+ isKey=1
+ fi
+
+ # reset for next token
+ parseStarted=0
+ token=
+ elif ((escaping)) && ((escaped)); then
+ escaping=0
+ escaped=0
+ fi
+ done
+}
+
+native_base_dir=$install_directory
+if [[ -z $install_directory ]]; then
+ native_base_dir=$(GetNativeInstallDirectory)
+fi
+
+install_bin="${native_base_dir}/bin"
+installed_any=false
+
+ReadGlobalJsonNativeTools
+
+if [[ ${#native_assets[@]} -eq 0 ]]; then
+ echo "No native tools defined in global.json"
+ exit 0;
+else
+ native_installer_dir="$scriptroot/native"
+ for index in "${!native_assets[@]}"; do
+ eval "${native_assets["$index"]}"
+
+ installer_path="$native_installer_dir/install-$KEY.sh"
+ installer_command="$installer_path"
+ installer_command+=" --baseuri $base_uri"
+ installer_command+=" --installpath $install_bin"
+ installer_command+=" --version $VALUE"
+ echo $installer_command
+
+ if [[ $force = true ]]; then
+ installer_command+=" --force"
+ fi
+
+ if [[ $clean = true ]]; then
+ installer_command+=" --clean"
+ fi
+
+ if [[ -a $installer_path ]]; then
+ $installer_command
+ if [[ $? != 0 ]]; then
+ if [[ $donotabortonfailure = true ]]; then
+ if [[ $donotdisplaywarnings != true ]]; then
+ Write-PipelineTelemetryError -category 'NativeToolsBootstrap' "Execution Failed"
+ fi
+ else
+ Write-PipelineTelemetryError -category 'NativeToolsBootstrap' "Execution Failed"
+ exit 1
+ fi
+ else
+ $installed_any = true
+ fi
+ else
+ if [[ $donotabortonfailure == true ]]; then
+ if [[ $donotdisplaywarnings != true ]]; then
+ Write-PipelineTelemetryError -category 'NativeToolsBootstrap' "Execution Failed: no install script"
+ fi
+ else
+ Write-PipelineTelemetryError -category 'NativeToolsBootstrap' "Execution Failed: no install script"
+ exit 1
+ fi
+ fi
+ done
+fi
+
+if [[ $clean = true ]]; then
+ exit 0
+fi
+
+if [[ -d $install_bin ]]; then
+ echo "Native tools are available from $install_bin"
+ echo "##vso[task.prependpath]$install_bin"
+else
+ if [[ $installed_any = true ]]; then
+ Write-PipelineTelemetryError -category 'NativeToolsBootstrap' "Native tools install directory does not exist, installation failed"
+ exit 1
+ fi
+fi
+
+exit 0
diff --git a/eng/common/internal-feed-operations.ps1 b/eng/common/internal-feed-operations.ps1
new file mode 100644
index 000000000..92b77347d
--- /dev/null
+++ b/eng/common/internal-feed-operations.ps1
@@ -0,0 +1,132 @@
+param(
+ [Parameter(Mandatory=$true)][string] $Operation,
+ [string] $AuthToken,
+ [string] $CommitSha,
+ [string] $RepoName,
+ [switch] $IsFeedPrivate
+)
+
+$ErrorActionPreference = 'Stop'
+Set-StrictMode -Version 2.0
+. $PSScriptRoot\tools.ps1
+
+# Sets VSS_NUGET_EXTERNAL_FEED_ENDPOINTS based on the "darc-int-*" feeds defined in NuGet.config. This is needed
+# in build agents by CredProvider to authenticate the restore requests to internal feeds as specified in
+# https://github.com/microsoft/artifacts-credprovider/blob/0f53327cd12fd893d8627d7b08a2171bf5852a41/README.md#environment-variables. This should ONLY be called from identified
+# internal builds
+function SetupCredProvider {
+ param(
+ [string] $AuthToken
+ )
+
+ # Install the Cred Provider NuGet plugin
+ Write-Host 'Setting up Cred Provider NuGet plugin in the agent...'
+ Write-Host "Getting 'installcredprovider.ps1' from 'https://github.com/microsoft/artifacts-credprovider'..."
+
+ $url = 'https://raw.githubusercontent.com/microsoft/artifacts-credprovider/master/helpers/installcredprovider.ps1'
+
+ Write-Host "Writing the contents of 'installcredprovider.ps1' locally..."
+ Invoke-WebRequest $url -OutFile installcredprovider.ps1
+
+ Write-Host 'Installing plugin...'
+ .\installcredprovider.ps1 -Force
+
+ Write-Host "Deleting local copy of 'installcredprovider.ps1'..."
+ Remove-Item .\installcredprovider.ps1
+
+ if (-Not("$env:USERPROFILE\.nuget\plugins\netcore")) {
+ Write-PipelineTelemetryError -Category 'Arcade' -Message 'CredProvider plugin was not installed correctly!'
+ ExitWithExitCode 1
+ }
+ else {
+ Write-Host 'CredProvider plugin was installed correctly!'
+ }
+
+ # Then, we set the 'VSS_NUGET_EXTERNAL_FEED_ENDPOINTS' environment variable to restore from the stable
+ # feeds successfully
+
+ $nugetConfigPath = Join-Path $RepoRoot "NuGet.config"
+
+ if (-Not (Test-Path -Path $nugetConfigPath)) {
+ Write-PipelineTelemetryError -Category 'Build' -Message 'NuGet.config file not found in repo root!'
+ ExitWithExitCode 1
+ }
+
+ $endpoints = New-Object System.Collections.ArrayList
+ $nugetConfigPackageSources = Select-Xml -Path $nugetConfigPath -XPath "//packageSources/add[contains(@key, 'darc-int-')]/@value" | foreach{$_.Node.Value}
+
+ if (($nugetConfigPackageSources | Measure-Object).Count -gt 0 ) {
+ foreach ($stableRestoreResource in $nugetConfigPackageSources) {
+ $trimmedResource = ([string]$stableRestoreResource).Trim()
+ [void]$endpoints.Add(@{endpoint="$trimmedResource"; password="$AuthToken"})
+ }
+ }
+
+ if (($endpoints | Measure-Object).Count -gt 0) {
+ $endpointCredentials = @{endpointCredentials=$endpoints} | ConvertTo-Json -Compress
+
+ # Create the environment variables the AzDo way
+ Write-LoggingCommand -Area 'task' -Event 'setvariable' -Data $endpointCredentials -Properties @{
+ 'variable' = 'VSS_NUGET_EXTERNAL_FEED_ENDPOINTS'
+ 'issecret' = 'false'
+ }
+
+ # We don't want sessions cached since we will be updating the endpoints quite frequently
+ Write-LoggingCommand -Area 'task' -Event 'setvariable' -Data 'False' -Properties @{
+ 'variable' = 'NUGET_CREDENTIALPROVIDER_SESSIONTOKENCACHE_ENABLED'
+ 'issecret' = 'false'
+ }
+ }
+ else
+ {
+ Write-Host 'No internal endpoints found in NuGet.config'
+ }
+}
+
+#Workaround for https://github.com/microsoft/msbuild/issues/4430
+function InstallDotNetSdkAndRestoreArcade {
+ $dotnetTempDir = Join-Path $RepoRoot "dotnet"
+ $dotnetSdkVersion="2.1.507" # After experimentation we know this version works when restoring the SDK (compared to 3.0.*)
+ $dotnet = "$dotnetTempDir\dotnet.exe"
+ $restoreProjPath = "$PSScriptRoot\restore.proj"
+
+ Write-Host "Installing dotnet SDK version $dotnetSdkVersion to restore Arcade SDK..."
+ InstallDotNetSdk "$dotnetTempDir" "$dotnetSdkVersion"
+
+ '' | Out-File "$restoreProjPath"
+
+ & $dotnet restore $restoreProjPath
+
+ Write-Host 'Arcade SDK restored!'
+
+ if (Test-Path -Path $restoreProjPath) {
+ Remove-Item $restoreProjPath
+ }
+
+ if (Test-Path -Path $dotnetTempDir) {
+ Remove-Item $dotnetTempDir -Recurse
+ }
+}
+
+try {
+ Push-Location $PSScriptRoot
+
+ if ($Operation -like 'setup') {
+ SetupCredProvider $AuthToken
+ }
+ elseif ($Operation -like 'install-restore') {
+ InstallDotNetSdkAndRestoreArcade
+ }
+ else {
+ Write-PipelineTelemetryError -Category 'Arcade' -Message "Unknown operation '$Operation'!"
+ ExitWithExitCode 1
+ }
+}
+catch {
+ Write-Host $_.ScriptStackTrace
+ Write-PipelineTelemetryError -Category 'Arcade' -Message $_
+ ExitWithExitCode 1
+}
+finally {
+ Pop-Location
+}
diff --git a/eng/common/internal-feed-operations.sh b/eng/common/internal-feed-operations.sh
new file mode 100644
index 000000000..9378223ba
--- /dev/null
+++ b/eng/common/internal-feed-operations.sh
@@ -0,0 +1,141 @@
+#!/usr/bin/env bash
+
+set -e
+
+# Sets VSS_NUGET_EXTERNAL_FEED_ENDPOINTS based on the "darc-int-*" feeds defined in NuGet.config. This is needed
+# in build agents by CredProvider to authenticate the restore requests to internal feeds as specified in
+# https://github.com/microsoft/artifacts-credprovider/blob/0f53327cd12fd893d8627d7b08a2171bf5852a41/README.md#environment-variables.
+# This should ONLY be called from identified internal builds
+function SetupCredProvider {
+ local authToken=$1
+
+ # Install the Cred Provider NuGet plugin
+ echo "Setting up Cred Provider NuGet plugin in the agent..."...
+ echo "Getting 'installcredprovider.ps1' from 'https://github.com/microsoft/artifacts-credprovider'..."
+
+ local url="https://raw.githubusercontent.com/microsoft/artifacts-credprovider/master/helpers/installcredprovider.sh"
+
+ echo "Writing the contents of 'installcredprovider.ps1' locally..."
+ local installcredproviderPath="installcredprovider.sh"
+ if command -v curl > /dev/null; then
+ curl $url > "$installcredproviderPath"
+ else
+ wget -q -O "$installcredproviderPath" "$url"
+ fi
+
+ echo "Installing plugin..."
+ . "$installcredproviderPath"
+
+ echo "Deleting local copy of 'installcredprovider.sh'..."
+ rm installcredprovider.sh
+
+ if [ ! -d "$HOME/.nuget/plugins" ]; then
+ Write-PipelineTelemetryError -category 'Build' 'CredProvider plugin was not installed correctly!'
+ ExitWithExitCode 1
+ else
+ echo "CredProvider plugin was installed correctly!"
+ fi
+
+ # Then, we set the 'VSS_NUGET_EXTERNAL_FEED_ENDPOINTS' environment variable to restore from the stable
+ # feeds successfully
+
+ local nugetConfigPath="{$repo_root}NuGet.config"
+
+ if [ ! "$nugetConfigPath" ]; then
+ Write-PipelineTelemetryError -category 'Build' "NuGet.config file not found in repo's root!"
+ ExitWithExitCode 1
+ fi
+
+ local endpoints='['
+ local nugetConfigPackageValues=`cat "$nugetConfigPath" | grep "key=\"darc-int-"`
+ local pattern="value=\"(.*)\""
+
+ for value in $nugetConfigPackageValues
+ do
+ if [[ $value =~ $pattern ]]; then
+ local endpoint="${BASH_REMATCH[1]}"
+ endpoints+="{\"endpoint\": \"$endpoint\", \"password\": \"$authToken\"},"
+ fi
+ done
+
+ endpoints=${endpoints%?}
+ endpoints+=']'
+
+ if [ ${#endpoints} -gt 2 ]; then
+ local endpointCredentials="{\"endpointCredentials\": "$endpoints"}"
+
+ echo "##vso[task.setvariable variable=VSS_NUGET_EXTERNAL_FEED_ENDPOINTS]$endpointCredentials"
+ echo "##vso[task.setvariable variable=NUGET_CREDENTIALPROVIDER_SESSIONTOKENCACHE_ENABLED]False"
+ else
+ echo "No internal endpoints found in NuGet.config"
+ fi
+}
+
+# Workaround for https://github.com/microsoft/msbuild/issues/4430
+function InstallDotNetSdkAndRestoreArcade {
+ local dotnetTempDir="$repo_root/dotnet"
+ local dotnetSdkVersion="2.1.507" # After experimentation we know this version works when restoring the SDK (compared to 3.0.*)
+ local restoreProjPath="$repo_root/eng/common/restore.proj"
+
+ echo "Installing dotnet SDK version $dotnetSdkVersion to restore Arcade SDK..."
+ echo "" > "$restoreProjPath"
+
+ InstallDotNetSdk "$dotnetTempDir" "$dotnetSdkVersion"
+
+ local res=`$dotnetTempDir/dotnet restore $restoreProjPath`
+ echo "Arcade SDK restored!"
+
+ # Cleanup
+ if [ "$restoreProjPath" ]; then
+ rm "$restoreProjPath"
+ fi
+
+ if [ "$dotnetTempDir" ]; then
+ rm -r $dotnetTempDir
+ fi
+}
+
+source="${BASH_SOURCE[0]}"
+operation=''
+authToken=''
+repoName=''
+
+while [[ $# > 0 ]]; do
+ opt="$(echo "$1" | tr "[:upper:]" "[:lower:]")"
+ case "$opt" in
+ --operation)
+ operation=$2
+ shift
+ ;;
+ --authtoken)
+ authToken=$2
+ shift
+ ;;
+ *)
+ echo "Invalid argument: $1"
+ usage
+ exit 1
+ ;;
+ esac
+
+ shift
+done
+
+while [[ -h "$source" ]]; do
+ scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+ source="$(readlink "$source")"
+ # if $source was a relative symlink, we need to resolve it relative to the path where the
+ # symlink file was located
+ [[ $source != /* ]] && source="$scriptroot/$source"
+done
+scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+
+. "$scriptroot/tools.sh"
+
+if [ "$operation" = "setup" ]; then
+ SetupCredProvider $authToken
+elif [ "$operation" = "install-restore" ]; then
+ InstallDotNetSdkAndRestoreArcade
+else
+ echo "Unknown operation '$operation'!"
+fi
diff --git a/eng/common/internal/Directory.Build.props b/eng/common/internal/Directory.Build.props
new file mode 100644
index 000000000..dbf99d82a
--- /dev/null
+++ b/eng/common/internal/Directory.Build.props
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/eng/common/internal/Tools.csproj b/eng/common/internal/Tools.csproj
new file mode 100644
index 000000000..f46d5efe2
--- /dev/null
+++ b/eng/common/internal/Tools.csproj
@@ -0,0 +1,28 @@
+
+
+
+
+ net472
+ false
+ false
+
+
+
+
+
+
+
+
+
+
+ https://devdiv.pkgs.visualstudio.com/_packaging/dotnet-core-internal-tooling/nuget/v3/index.json;
+
+
+ $(RestoreSources);
+ https://devdiv.pkgs.visualstudio.com/_packaging/VS/nuget/v3/index.json;
+
+
+
+
+
+
diff --git a/eng/common/msbuild.ps1 b/eng/common/msbuild.ps1
new file mode 100644
index 000000000..eea19cd84
--- /dev/null
+++ b/eng/common/msbuild.ps1
@@ -0,0 +1,27 @@
+[CmdletBinding(PositionalBinding=$false)]
+Param(
+ [string] $verbosity = 'minimal',
+ [bool] $warnAsError = $true,
+ [bool] $nodeReuse = $true,
+ [switch] $ci,
+ [switch] $prepareMachine,
+ [switch] $excludePrereleaseVS,
+ [Parameter(ValueFromRemainingArguments=$true)][String[]]$extraArgs
+)
+
+. $PSScriptRoot\tools.ps1
+
+try {
+ if ($ci) {
+ $nodeReuse = $false
+ }
+
+ MSBuild @extraArgs
+}
+catch {
+ Write-Host $_.ScriptStackTrace
+ Write-PipelineTelemetryError -Category 'Build' -Message $_
+ ExitWithExitCode 1
+}
+
+ExitWithExitCode 0
\ No newline at end of file
diff --git a/eng/common/msbuild.sh b/eng/common/msbuild.sh
new file mode 100644
index 000000000..20d3dad54
--- /dev/null
+++ b/eng/common/msbuild.sh
@@ -0,0 +1,58 @@
+#!/usr/bin/env bash
+
+source="${BASH_SOURCE[0]}"
+
+# resolve $source until the file is no longer a symlink
+while [[ -h "$source" ]]; do
+ scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+ source="$(readlink "$source")"
+ # if $source was a relative symlink, we need to resolve it relative to the path where the
+ # symlink file was located
+ [[ $source != /* ]] && source="$scriptroot/$source"
+done
+scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+
+verbosity='minimal'
+warn_as_error=true
+node_reuse=true
+prepare_machine=false
+extra_args=''
+
+while (($# > 0)); do
+ lowerI="$(echo $1 | tr "[:upper:]" "[:lower:]")"
+ case $lowerI in
+ --verbosity)
+ verbosity=$2
+ shift 2
+ ;;
+ --warnaserror)
+ warn_as_error=$2
+ shift 2
+ ;;
+ --nodereuse)
+ node_reuse=$2
+ shift 2
+ ;;
+ --ci)
+ ci=true
+ shift 1
+ ;;
+ --preparemachine)
+ prepare_machine=true
+ shift 1
+ ;;
+ *)
+ extra_args="$extra_args $1"
+ shift 1
+ ;;
+ esac
+done
+
+. "$scriptroot/tools.sh"
+
+if [[ "$ci" == true ]]; then
+ node_reuse=false
+fi
+
+MSBuild $extra_args
+ExitWithExitCode 0
diff --git a/eng/common/native/CommonLibrary.psm1 b/eng/common/native/CommonLibrary.psm1
new file mode 100644
index 000000000..adf707c8f
--- /dev/null
+++ b/eng/common/native/CommonLibrary.psm1
@@ -0,0 +1,399 @@
+<#
+.SYNOPSIS
+Helper module to install an archive to a directory
+
+.DESCRIPTION
+Helper module to download and extract an archive to a specified directory
+
+.PARAMETER Uri
+Uri of artifact to download
+
+.PARAMETER InstallDirectory
+Directory to extract artifact contents to
+
+.PARAMETER Force
+Force download / extraction if file or contents already exist. Default = False
+
+.PARAMETER DownloadRetries
+Total number of retry attempts. Default = 5
+
+.PARAMETER RetryWaitTimeInSeconds
+Wait time between retry attempts in seconds. Default = 30
+
+.NOTES
+Returns False if download or extraction fail, True otherwise
+#>
+function DownloadAndExtract {
+ [CmdletBinding(PositionalBinding=$false)]
+ Param (
+ [Parameter(Mandatory=$True)]
+ [string] $Uri,
+ [Parameter(Mandatory=$True)]
+ [string] $InstallDirectory,
+ [switch] $Force = $False,
+ [int] $DownloadRetries = 5,
+ [int] $RetryWaitTimeInSeconds = 30
+ )
+ # Define verbose switch if undefined
+ $Verbose = $VerbosePreference -Eq "Continue"
+
+ $TempToolPath = CommonLibrary\Get-TempPathFilename -Path $Uri
+
+ # Download native tool
+ $DownloadStatus = CommonLibrary\Get-File -Uri $Uri `
+ -Path $TempToolPath `
+ -DownloadRetries $DownloadRetries `
+ -RetryWaitTimeInSeconds $RetryWaitTimeInSeconds `
+ -Force:$Force `
+ -Verbose:$Verbose
+
+ if ($DownloadStatus -Eq $False) {
+ Write-Error "Download failed from $Uri"
+ return $False
+ }
+
+ # Extract native tool
+ $UnzipStatus = CommonLibrary\Expand-Zip -ZipPath $TempToolPath `
+ -OutputDirectory $InstallDirectory `
+ -Force:$Force `
+ -Verbose:$Verbose
+
+ if ($UnzipStatus -Eq $False) {
+ # Retry Download one more time with Force=true
+ $DownloadRetryStatus = CommonLibrary\Get-File -Uri $Uri `
+ -Path $TempToolPath `
+ -DownloadRetries 1 `
+ -RetryWaitTimeInSeconds $RetryWaitTimeInSeconds `
+ -Force:$True `
+ -Verbose:$Verbose
+
+ if ($DownloadRetryStatus -Eq $False) {
+ Write-Error "Last attempt of download failed as well"
+ return $False
+ }
+
+ # Retry unzip again one more time with Force=true
+ $UnzipRetryStatus = CommonLibrary\Expand-Zip -ZipPath $TempToolPath `
+ -OutputDirectory $InstallDirectory `
+ -Force:$True `
+ -Verbose:$Verbose
+ if ($UnzipRetryStatus -Eq $False)
+ {
+ Write-Error "Last attempt of unzip failed as well"
+ # Clean up partial zips and extracts
+ if (Test-Path $TempToolPath) {
+ Remove-Item $TempToolPath -Force
+ }
+ if (Test-Path $InstallDirectory) {
+ Remove-Item $InstallDirectory -Force -Recurse
+ }
+ return $False
+ }
+ }
+
+ return $True
+}
+
+<#
+.SYNOPSIS
+Download a file, retry on failure
+
+.DESCRIPTION
+Download specified file and retry if attempt fails
+
+.PARAMETER Uri
+Uri of file to download. If Uri is a local path, the file will be copied instead of downloaded
+
+.PARAMETER Path
+Path to download or copy uri file to
+
+.PARAMETER Force
+Overwrite existing file if present. Default = False
+
+.PARAMETER DownloadRetries
+Total number of retry attempts. Default = 5
+
+.PARAMETER RetryWaitTimeInSeconds
+Wait time between retry attempts in seconds Default = 30
+
+#>
+function Get-File {
+ [CmdletBinding(PositionalBinding=$false)]
+ Param (
+ [Parameter(Mandatory=$True)]
+ [string] $Uri,
+ [Parameter(Mandatory=$True)]
+ [string] $Path,
+ [int] $DownloadRetries = 5,
+ [int] $RetryWaitTimeInSeconds = 30,
+ [switch] $Force = $False
+ )
+ $Attempt = 0
+
+ if ($Force) {
+ if (Test-Path $Path) {
+ Remove-Item $Path -Force
+ }
+ }
+ if (Test-Path $Path) {
+ Write-Host "File '$Path' already exists, skipping download"
+ return $True
+ }
+
+ $DownloadDirectory = Split-Path -ErrorAction Ignore -Path "$Path" -Parent
+ if (-Not (Test-Path $DownloadDirectory)) {
+ New-Item -path $DownloadDirectory -force -itemType "Directory" | Out-Null
+ }
+
+ $TempPath = "$Path.tmp"
+ if (Test-Path -IsValid -Path $Uri) {
+ Write-Verbose "'$Uri' is a file path, copying temporarily to '$TempPath'"
+ Copy-Item -Path $Uri -Destination $TempPath
+ Write-Verbose "Moving temporary file to '$Path'"
+ Move-Item -Path $TempPath -Destination $Path
+ return $?
+ }
+ else {
+ Write-Verbose "Downloading $Uri"
+ # Don't display the console progress UI - it's a huge perf hit
+ $ProgressPreference = 'SilentlyContinue'
+ while($Attempt -Lt $DownloadRetries)
+ {
+ try {
+ Invoke-WebRequest -UseBasicParsing -Uri $Uri -OutFile $TempPath
+ Write-Verbose "Downloaded to temporary location '$TempPath'"
+ Move-Item -Path $TempPath -Destination $Path
+ Write-Verbose "Moved temporary file to '$Path'"
+ return $True
+ }
+ catch {
+ $Attempt++
+ if ($Attempt -Lt $DownloadRetries) {
+ $AttemptsLeft = $DownloadRetries - $Attempt
+ Write-Warning "Download failed, $AttemptsLeft attempts remaining, will retry in $RetryWaitTimeInSeconds seconds"
+ Start-Sleep -Seconds $RetryWaitTimeInSeconds
+ }
+ else {
+ Write-Error $_
+ Write-Error $_.Exception
+ }
+ }
+ }
+ }
+
+ return $False
+}
+
+<#
+.SYNOPSIS
+Generate a shim for a native tool
+
+.DESCRIPTION
+Creates a wrapper script (shim) that passes arguments forward to native tool assembly
+
+.PARAMETER ShimName
+The name of the shim
+
+.PARAMETER ShimDirectory
+The directory where shims are stored
+
+.PARAMETER ToolFilePath
+Path to file that shim forwards to
+
+.PARAMETER Force
+Replace shim if already present. Default = False
+
+.NOTES
+Returns $True if generating shim succeeds, $False otherwise
+#>
+function New-ScriptShim {
+ [CmdletBinding(PositionalBinding=$false)]
+ Param (
+ [Parameter(Mandatory=$True)]
+ [string] $ShimName,
+ [Parameter(Mandatory=$True)]
+ [string] $ShimDirectory,
+ [Parameter(Mandatory=$True)]
+ [string] $ToolFilePath,
+ [Parameter(Mandatory=$True)]
+ [string] $BaseUri,
+ [switch] $Force
+ )
+ try {
+ Write-Verbose "Generating '$ShimName' shim"
+
+ if (-Not (Test-Path $ToolFilePath)){
+ Write-Error "Specified tool file path '$ToolFilePath' does not exist"
+ return $False
+ }
+
+ # WinShimmer is a small .NET Framework program that creates .exe shims to bootstrapped programs
+ # Many of the checks for installed programs expect a .exe extension for Windows tools, rather
+ # than a .bat or .cmd file.
+ # Source: https://github.com/dotnet/arcade/tree/master/src/WinShimmer
+ if (-Not (Test-Path "$ShimDirectory\WinShimmer\winshimmer.exe")) {
+ $InstallStatus = DownloadAndExtract -Uri "$BaseUri/windows/winshimmer/WinShimmer.zip" `
+ -InstallDirectory $ShimDirectory\WinShimmer `
+ -Force:$Force `
+ -DownloadRetries 2 `
+ -RetryWaitTimeInSeconds 5 `
+ -Verbose:$Verbose
+ }
+
+ if ((Test-Path (Join-Path $ShimDirectory "$ShimName.exe"))) {
+ Write-Host "$ShimName.exe already exists; replacing..."
+ Remove-Item (Join-Path $ShimDirectory "$ShimName.exe")
+ }
+
+ & "$ShimDirectory\WinShimmer\winshimmer.exe" $ShimName $ToolFilePath $ShimDirectory
+ return $True
+ }
+ catch {
+ Write-Host $_
+ Write-Host $_.Exception
+ return $False
+ }
+}
+
+<#
+.SYNOPSIS
+Returns the machine architecture of the host machine
+
+.NOTES
+Returns 'x64' on 64 bit machines
+ Returns 'x86' on 32 bit machines
+#>
+function Get-MachineArchitecture {
+ $ProcessorArchitecture = $Env:PROCESSOR_ARCHITECTURE
+ $ProcessorArchitectureW6432 = $Env:PROCESSOR_ARCHITEW6432
+ if($ProcessorArchitecture -Eq "X86")
+ {
+ if(($ProcessorArchitectureW6432 -Eq "") -Or
+ ($ProcessorArchitectureW6432 -Eq "X86")) {
+ return "x86"
+ }
+ $ProcessorArchitecture = $ProcessorArchitectureW6432
+ }
+ if (($ProcessorArchitecture -Eq "AMD64") -Or
+ ($ProcessorArchitecture -Eq "IA64") -Or
+ ($ProcessorArchitecture -Eq "ARM64")) {
+ return "x64"
+ }
+ return "x86"
+}
+
+<#
+.SYNOPSIS
+Get the name of a temporary folder under the native install directory
+#>
+function Get-TempDirectory {
+ return Join-Path (Get-NativeInstallDirectory) "temp/"
+}
+
+function Get-TempPathFilename {
+ [CmdletBinding(PositionalBinding=$false)]
+ Param (
+ [Parameter(Mandatory=$True)]
+ [string] $Path
+ )
+ $TempDir = CommonLibrary\Get-TempDirectory
+ $TempFilename = Split-Path $Path -leaf
+ $TempPath = Join-Path $TempDir $TempFilename
+ return $TempPath
+}
+
+<#
+.SYNOPSIS
+Returns the base directory to use for native tool installation
+
+.NOTES
+Returns the value of the NETCOREENG_INSTALL_DIRECTORY if that environment variable
+is set, or otherwise returns an install directory under the %USERPROFILE%
+#>
+function Get-NativeInstallDirectory {
+ $InstallDir = $Env:NETCOREENG_INSTALL_DIRECTORY
+ if (!$InstallDir) {
+ $InstallDir = Join-Path $Env:USERPROFILE ".netcoreeng/native/"
+ }
+ return $InstallDir
+}
+
+<#
+.SYNOPSIS
+Unzip an archive
+
+.DESCRIPTION
+Powershell module to unzip an archive to a specified directory
+
+.PARAMETER ZipPath (Required)
+Path to archive to unzip
+
+.PARAMETER OutputDirectory (Required)
+Output directory for archive contents
+
+.PARAMETER Force
+Overwrite output directory contents if they already exist
+
+.NOTES
+- Returns True and does not perform an extraction if output directory already exists but Overwrite is not True.
+- Returns True if unzip operation is successful
+- Returns False if Overwrite is True and it is unable to remove contents of OutputDirectory
+- Returns False if unable to extract zip archive
+#>
+function Expand-Zip {
+ [CmdletBinding(PositionalBinding=$false)]
+ Param (
+ [Parameter(Mandatory=$True)]
+ [string] $ZipPath,
+ [Parameter(Mandatory=$True)]
+ [string] $OutputDirectory,
+ [switch] $Force
+ )
+
+ Write-Verbose "Extracting '$ZipPath' to '$OutputDirectory'"
+ try {
+ if ((Test-Path $OutputDirectory) -And (-Not $Force)) {
+ Write-Host "Directory '$OutputDirectory' already exists, skipping extract"
+ return $True
+ }
+ if (Test-Path $OutputDirectory) {
+ Write-Verbose "'Force' is 'True', but '$OutputDirectory' exists, removing directory"
+ Remove-Item $OutputDirectory -Force -Recurse
+ if ($? -Eq $False) {
+ Write-Error "Unable to remove '$OutputDirectory'"
+ return $False
+ }
+ }
+
+ $TempOutputDirectory = Join-Path "$(Split-Path -Parent $OutputDirectory)" "$(Split-Path -Leaf $OutputDirectory).tmp"
+ if (Test-Path $TempOutputDirectory) {
+ Remove-Item $TempOutputDirectory -Force -Recurse
+ }
+ New-Item -Path $TempOutputDirectory -Force -ItemType "Directory" | Out-Null
+
+ Add-Type -assembly "system.io.compression.filesystem"
+ [io.compression.zipfile]::ExtractToDirectory("$ZipPath", "$TempOutputDirectory")
+ if ($? -Eq $False) {
+ Write-Error "Unable to extract '$ZipPath'"
+ return $False
+ }
+
+ Move-Item -Path $TempOutputDirectory -Destination $OutputDirectory
+ }
+ catch {
+ Write-Host $_
+ Write-Host $_.Exception
+
+ return $False
+ }
+ return $True
+}
+
+export-modulemember -function DownloadAndExtract
+export-modulemember -function Expand-Zip
+export-modulemember -function Get-File
+export-modulemember -function Get-MachineArchitecture
+export-modulemember -function Get-NativeInstallDirectory
+export-modulemember -function Get-TempDirectory
+export-modulemember -function Get-TempPathFilename
+export-modulemember -function New-ScriptShim
diff --git a/eng/common/native/common-library.sh b/eng/common/native/common-library.sh
new file mode 100644
index 000000000..bf272dcf5
--- /dev/null
+++ b/eng/common/native/common-library.sh
@@ -0,0 +1,168 @@
+#!/usr/bin/env bash
+
+function GetNativeInstallDirectory {
+ local install_dir
+
+ if [[ -z $NETCOREENG_INSTALL_DIRECTORY ]]; then
+ install_dir=$HOME/.netcoreeng/native/
+ else
+ install_dir=$NETCOREENG_INSTALL_DIRECTORY
+ fi
+
+ echo $install_dir
+ return 0
+}
+
+function GetTempDirectory {
+
+ echo $(GetNativeInstallDirectory)temp/
+ return 0
+}
+
+function ExpandZip {
+ local zip_path=$1
+ local output_directory=$2
+ local force=${3:-false}
+
+ echo "Extracting $zip_path to $output_directory"
+ if [[ -d $output_directory ]] && [[ $force = false ]]; then
+ echo "Directory '$output_directory' already exists, skipping extract"
+ return 0
+ fi
+
+ if [[ -d $output_directory ]]; then
+ echo "'Force flag enabled, but '$output_directory' exists. Removing directory"
+ rm -rf $output_directory
+ if [[ $? != 0 ]]; then
+ Write-PipelineTelemetryError -category 'NativeToolsBootstrap' "Unable to remove '$output_directory'"
+ return 1
+ fi
+ fi
+
+ echo "Creating directory: '$output_directory'"
+ mkdir -p $output_directory
+
+ echo "Extracting archive"
+ tar -xf $zip_path -C $output_directory
+ if [[ $? != 0 ]]; then
+ Write-PipelineTelemetryError -category 'NativeToolsBootstrap' "Unable to extract '$zip_path'"
+ return 1
+ fi
+
+ return 0
+}
+
+function GetCurrentOS {
+ local unameOut="$(uname -s)"
+ case $unameOut in
+ Linux*) echo "Linux";;
+ Darwin*) echo "MacOS";;
+ esac
+ return 0
+}
+
+function GetFile {
+ local uri=$1
+ local path=$2
+ local force=${3:-false}
+ local download_retries=${4:-5}
+ local retry_wait_time_seconds=${5:-30}
+
+ if [[ -f $path ]]; then
+ if [[ $force = false ]]; then
+ echo "File '$path' already exists. Skipping download"
+ return 0
+ else
+ rm -rf $path
+ fi
+ fi
+
+ if [[ -f $uri ]]; then
+ echo "'$uri' is a file path, copying file to '$path'"
+ cp $uri $path
+ return $?
+ fi
+
+ echo "Downloading $uri"
+ # Use curl if available, otherwise use wget
+ if command -v curl > /dev/null; then
+ curl "$uri" -sSL --retry $download_retries --retry-delay $retry_wait_time_seconds --create-dirs -o "$path" --fail
+ else
+ wget -q -O "$path" "$uri" --tries="$download_retries"
+ fi
+
+ return $?
+}
+
+function GetTempPathFileName {
+ local path=$1
+
+ local temp_dir=$(GetTempDirectory)
+ local temp_file_name=$(basename $path)
+ echo $temp_dir$temp_file_name
+ return 0
+}
+
+function DownloadAndExtract {
+ local uri=$1
+ local installDir=$2
+ local force=${3:-false}
+ local download_retries=${4:-5}
+ local retry_wait_time_seconds=${5:-30}
+
+ local temp_tool_path=$(GetTempPathFileName $uri)
+
+ echo "downloading to: $temp_tool_path"
+
+ # Download file
+ GetFile "$uri" "$temp_tool_path" $force $download_retries $retry_wait_time_seconds
+ if [[ $? != 0 ]]; then
+ Write-PipelineTelemetryError -category 'NativeToolsBootstrap' "Failed to download '$uri' to '$temp_tool_path'."
+ return 1
+ fi
+
+ # Extract File
+ echo "extracting from $temp_tool_path to $installDir"
+ ExpandZip "$temp_tool_path" "$installDir" $force $download_retries $retry_wait_time_seconds
+ if [[ $? != 0 ]]; then
+ Write-PipelineTelemetryError -category 'NativeToolsBootstrap' "Failed to extract '$temp_tool_path' to '$installDir'."
+ return 1
+ fi
+
+ return 0
+}
+
+function NewScriptShim {
+ local shimpath=$1
+ local tool_file_path=$2
+ local force=${3:-false}
+
+ echo "Generating '$shimpath' shim"
+ if [[ -f $shimpath ]]; then
+ if [[ $force = false ]]; then
+ echo "File '$shimpath' already exists." >&2
+ return 1
+ else
+ rm -rf $shimpath
+ fi
+ fi
+
+ if [[ ! -f $tool_file_path ]]; then
+ Write-PipelineTelemetryError -category 'NativeToolsBootstrap' "Specified tool file path:'$tool_file_path' does not exist"
+ return 1
+ fi
+
+ local shim_contents=$'#!/usr/bin/env bash\n'
+ shim_contents+="SHIMARGS="$'$1\n'
+ shim_contents+="$tool_file_path"$' $SHIMARGS\n'
+
+ # Write shim file
+ echo "$shim_contents" > $shimpath
+
+ chmod +x $shimpath
+
+ echo "Finished generating shim '$shimpath'"
+
+ return $?
+}
+
diff --git a/eng/common/native/find-native-compiler.sh b/eng/common/native/find-native-compiler.sh
new file mode 100644
index 000000000..aed19d07d
--- /dev/null
+++ b/eng/common/native/find-native-compiler.sh
@@ -0,0 +1,121 @@
+#!/usr/bin/env bash
+#
+# This file locates the native compiler with the given name and version and sets the environment variables to locate it.
+#
+
+source="${BASH_SOURCE[0]}"
+
+# resolve $SOURCE until the file is no longer a symlink
+while [[ -h $source ]]; do
+ scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+ source="$(readlink "$source")"
+
+ # if $source was a relative symlink, we need to resolve it relative to the path where the
+ # symlink file was located
+ [[ $source != /* ]] && source="$scriptroot/$source"
+done
+scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+
+if [ $# -lt 0 ]
+then
+ echo "Usage..."
+ echo "find-native-compiler.sh "
+ echo "Specify the name of compiler (clang or gcc)."
+ echo "Specify the major version of compiler."
+ echo "Specify the minor version of compiler."
+ exit 1
+fi
+
+. $scriptroot/../pipeline-logging-functions.sh
+
+compiler="$1"
+cxxCompiler="$compiler++"
+majorVersion="$2"
+minorVersion="$3"
+
+if [ "$compiler" = "gcc" ]; then cxxCompiler="g++"; fi
+
+check_version_exists() {
+ desired_version=-1
+
+ # Set up the environment to be used for building with the desired compiler.
+ if command -v "$compiler-$1.$2" > /dev/null; then
+ desired_version="-$1.$2"
+ elif command -v "$compiler$1$2" > /dev/null; then
+ desired_version="$1$2"
+ elif command -v "$compiler-$1$2" > /dev/null; then
+ desired_version="-$1$2"
+ fi
+
+ echo "$desired_version"
+}
+
+if [ -z "$CLR_CC" ]; then
+
+ # Set default versions
+ if [ -z "$majorVersion" ]; then
+ # note: gcc (all versions) and clang versions higher than 6 do not have minor version in file name, if it is zero.
+ if [ "$compiler" = "clang" ]; then versions=( 9 8 7 6.0 5.0 4.0 3.9 3.8 3.7 3.6 3.5 )
+ elif [ "$compiler" = "gcc" ]; then versions=( 9 8 7 6 5 4.9 ); fi
+
+ for version in "${versions[@]}"; do
+ parts=(${version//./ })
+ desired_version="$(check_version_exists "${parts[0]}" "${parts[1]}")"
+ if [ "$desired_version" != "-1" ]; then majorVersion="${parts[0]}"; break; fi
+ done
+
+ if [ -z "$majorVersion" ]; then
+ if command -v "$compiler" > /dev/null; then
+ if [ "$(uname)" != "Darwin" ]; then
+ Write-PipelineTelemetryError -category "Build" -type "warning" "Specific version of $compiler not found, falling back to use the one in PATH."
+ fi
+ export CC="$(command -v "$compiler")"
+ export CXX="$(command -v "$cxxCompiler")"
+ else
+ Write-PipelineTelemetryError -category "Build" "No usable version of $compiler found."
+ exit 1
+ fi
+ else
+ if [ "$compiler" = "clang" ] && [ "$majorVersion" -lt 5 ]; then
+ if [ "$build_arch" = "arm" ] || [ "$build_arch" = "armel" ]; then
+ if command -v "$compiler" > /dev/null; then
+ Write-PipelineTelemetryError -category "Build" -type "warning" "Found clang version $majorVersion which is not supported on arm/armel architectures, falling back to use clang from PATH."
+ export CC="$(command -v "$compiler")"
+ export CXX="$(command -v "$cxxCompiler")"
+ else
+ Write-PipelineTelemetryError -category "Build" "Found clang version $majorVersion which is not supported on arm/armel architectures, and there is no clang in PATH."
+ exit 1
+ fi
+ fi
+ fi
+ fi
+ else
+ desired_version="$(check_version_exists "$majorVersion" "$minorVersion")"
+ if [ "$desired_version" = "-1" ]; then
+ Write-PipelineTelemetryError -category "Build" "Could not find specific version of $compiler: $majorVersion $minorVersion."
+ exit 1
+ fi
+ fi
+
+ if [ -z "$CC" ]; then
+ export CC="$(command -v "$compiler$desired_version")"
+ export CXX="$(command -v "$cxxCompiler$desired_version")"
+ if [ -z "$CXX" ]; then export CXX="$(command -v "$cxxCompiler")"; fi
+ fi
+else
+ if [ ! -f "$CLR_CC" ]; then
+ Write-PipelineTelemetryError -category "Build" "CLR_CC is set but path '$CLR_CC' does not exist"
+ exit 1
+ fi
+ export CC="$CLR_CC"
+ export CXX="$CLR_CXX"
+fi
+
+if [ -z "$CC" ]; then
+ Write-PipelineTelemetryError -category "Build" "Unable to find $compiler."
+ exit 1
+fi
+
+export CCC_CC="$CC"
+export CCC_CXX="$CXX"
+export SCAN_BUILD_COMMAND="$(command -v "scan-build$desired_version")"
diff --git a/eng/common/native/install-cmake-test.sh b/eng/common/native/install-cmake-test.sh
new file mode 100644
index 000000000..8a5e7cf0d
--- /dev/null
+++ b/eng/common/native/install-cmake-test.sh
@@ -0,0 +1,117 @@
+#!/usr/bin/env bash
+
+source="${BASH_SOURCE[0]}"
+scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+
+. $scriptroot/common-library.sh
+
+base_uri=
+install_path=
+version=
+clean=false
+force=false
+download_retries=5
+retry_wait_time_seconds=30
+
+while (($# > 0)); do
+ lowerI="$(echo $1 | tr "[:upper:]" "[:lower:]")"
+ case $lowerI in
+ --baseuri)
+ base_uri=$2
+ shift 2
+ ;;
+ --installpath)
+ install_path=$2
+ shift 2
+ ;;
+ --version)
+ version=$2
+ shift 2
+ ;;
+ --clean)
+ clean=true
+ shift 1
+ ;;
+ --force)
+ force=true
+ shift 1
+ ;;
+ --downloadretries)
+ download_retries=$2
+ shift 2
+ ;;
+ --retrywaittimeseconds)
+ retry_wait_time_seconds=$2
+ shift 2
+ ;;
+ --help)
+ echo "Common settings:"
+ echo " --baseuri Base file directory or Url wrom which to acquire tool archives"
+ echo " --installpath Base directory to install native tool to"
+ echo " --clean Don't install the tool, just clean up the current install of the tool"
+ echo " --force Force install of tools even if they previously exist"
+ echo " --help Print help and exit"
+ echo ""
+ echo "Advanced settings:"
+ echo " --downloadretries Total number of retry attempts"
+ echo " --retrywaittimeseconds Wait time between retry attempts in seconds"
+ echo ""
+ exit 0
+ ;;
+ esac
+done
+
+tool_name="cmake-test"
+tool_os=$(GetCurrentOS)
+tool_folder="$(echo $tool_os | tr "[:upper:]" "[:lower:]")"
+tool_arch="x86_64"
+tool_name_moniker="$tool_name-$version-$tool_os-$tool_arch"
+tool_install_directory="$install_path/$tool_name/$version"
+tool_file_path="$tool_install_directory/$tool_name_moniker/bin/$tool_name"
+shim_path="$install_path/$tool_name.sh"
+uri="${base_uri}/$tool_folder/$tool_name/$tool_name_moniker.tar.gz"
+
+# Clean up tool and installers
+if [[ $clean = true ]]; then
+ echo "Cleaning $tool_install_directory"
+ if [[ -d $tool_install_directory ]]; then
+ rm -rf $tool_install_directory
+ fi
+
+ echo "Cleaning $shim_path"
+ if [[ -f $shim_path ]]; then
+ rm -rf $shim_path
+ fi
+
+ tool_temp_path=$(GetTempPathFileName $uri)
+ echo "Cleaning $tool_temp_path"
+ if [[ -f $tool_temp_path ]]; then
+ rm -rf $tool_temp_path
+ fi
+
+ exit 0
+fi
+
+# Install tool
+if [[ -f $tool_file_path ]] && [[ $force = false ]]; then
+ echo "$tool_name ($version) already exists, skipping install"
+ exit 0
+fi
+
+DownloadAndExtract $uri $tool_install_directory $force $download_retries $retry_wait_time_seconds
+
+if [[ $? != 0 ]]; then
+ Write-PipelineTelemetryError -category 'NativeToolsBootstrap' 'Installation failed'
+ exit 1
+fi
+
+# Generate Shim
+# Always rewrite shims so that we are referencing the expected version
+NewScriptShim $shim_path $tool_file_path true
+
+if [[ $? != 0 ]]; then
+ Write-PipelineTelemetryError -category 'NativeToolsBootstrap' 'Shim generation failed'
+ exit 1
+fi
+
+exit 0
diff --git a/eng/common/native/install-cmake.sh b/eng/common/native/install-cmake.sh
new file mode 100644
index 000000000..de496beeb
--- /dev/null
+++ b/eng/common/native/install-cmake.sh
@@ -0,0 +1,117 @@
+#!/usr/bin/env bash
+
+source="${BASH_SOURCE[0]}"
+scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
+
+. $scriptroot/common-library.sh
+
+base_uri=
+install_path=
+version=
+clean=false
+force=false
+download_retries=5
+retry_wait_time_seconds=30
+
+while (($# > 0)); do
+ lowerI="$(echo $1 | tr "[:upper:]" "[:lower:]")"
+ case $lowerI in
+ --baseuri)
+ base_uri=$2
+ shift 2
+ ;;
+ --installpath)
+ install_path=$2
+ shift 2
+ ;;
+ --version)
+ version=$2
+ shift 2
+ ;;
+ --clean)
+ clean=true
+ shift 1
+ ;;
+ --force)
+ force=true
+ shift 1
+ ;;
+ --downloadretries)
+ download_retries=$2
+ shift 2
+ ;;
+ --retrywaittimeseconds)
+ retry_wait_time_seconds=$2
+ shift 2
+ ;;
+ --help)
+ echo "Common settings:"
+ echo " --baseuri Base file directory or Url wrom which to acquire tool archives"
+ echo " --installpath Base directory to install native tool to"
+ echo " --clean Don't install the tool, just clean up the current install of the tool"
+ echo " --force Force install of tools even if they previously exist"
+ echo " --help Print help and exit"
+ echo ""
+ echo "Advanced settings:"
+ echo " --downloadretries Total number of retry attempts"
+ echo " --retrywaittimeseconds Wait time between retry attempts in seconds"
+ echo ""
+ exit 0
+ ;;
+ esac
+done
+
+tool_name="cmake"
+tool_os=$(GetCurrentOS)
+tool_folder="$(echo $tool_os | tr "[:upper:]" "[:lower:]")"
+tool_arch="x86_64"
+tool_name_moniker="$tool_name-$version-$tool_os-$tool_arch"
+tool_install_directory="$install_path/$tool_name/$version"
+tool_file_path="$tool_install_directory/$tool_name_moniker/bin/$tool_name"
+shim_path="$install_path/$tool_name.sh"
+uri="${base_uri}/$tool_folder/$tool_name/$tool_name_moniker.tar.gz"
+
+# Clean up tool and installers
+if [[ $clean = true ]]; then
+ echo "Cleaning $tool_install_directory"
+ if [[ -d $tool_install_directory ]]; then
+ rm -rf $tool_install_directory
+ fi
+
+ echo "Cleaning $shim_path"
+ if [[ -f $shim_path ]]; then
+ rm -rf $shim_path
+ fi
+
+ tool_temp_path=$(GetTempPathFileName $uri)
+ echo "Cleaning $tool_temp_path"
+ if [[ -f $tool_temp_path ]]; then
+ rm -rf $tool_temp_path
+ fi
+
+ exit 0
+fi
+
+# Install tool
+if [[ -f $tool_file_path ]] && [[ $force = false ]]; then
+ echo "$tool_name ($version) already exists, skipping install"
+ exit 0
+fi
+
+DownloadAndExtract $uri $tool_install_directory $force $download_retries $retry_wait_time_seconds
+
+if [[ $? != 0 ]]; then
+ Write-PipelineTelemetryError -category 'NativeToolsBootstrap' 'Installation failed'
+ exit 1
+fi
+
+# Generate Shim
+# Always rewrite shims so that we are referencing the expected version
+NewScriptShim $shim_path $tool_file_path true
+
+if [[ $? != 0 ]]; then
+ Write-PipelineTelemetryError -category 'NativeToolsBootstrap' 'Shim generation failed'
+ exit 1
+fi
+
+exit 0
diff --git a/eng/common/native/install-tool.ps1 b/eng/common/native/install-tool.ps1
new file mode 100644
index 000000000..78f2d84a4
--- /dev/null
+++ b/eng/common/native/install-tool.ps1
@@ -0,0 +1,132 @@
+<#
+.SYNOPSIS
+Install native tool
+
+.DESCRIPTION
+Install cmake native tool from Azure blob storage
+
+.PARAMETER InstallPath
+Base directory to install native tool to
+
+.PARAMETER BaseUri
+Base file directory or Url from which to acquire tool archives
+
+.PARAMETER CommonLibraryDirectory
+Path to folder containing common library modules
+
+.PARAMETER Force
+Force install of tools even if they previously exist
+
+.PARAMETER Clean
+Don't install the tool, just clean up the current install of the tool
+
+.PARAMETER DownloadRetries
+Total number of retry attempts
+
+.PARAMETER RetryWaitTimeInSeconds
+Wait time between retry attempts in seconds
+
+.NOTES
+Returns 0 if install succeeds, 1 otherwise
+#>
+[CmdletBinding(PositionalBinding=$false)]
+Param (
+ [Parameter(Mandatory=$True)]
+ [string] $ToolName,
+ [Parameter(Mandatory=$True)]
+ [string] $InstallPath,
+ [Parameter(Mandatory=$True)]
+ [string] $BaseUri,
+ [Parameter(Mandatory=$True)]
+ [string] $Version,
+ [string] $CommonLibraryDirectory = $PSScriptRoot,
+ [switch] $Force = $False,
+ [switch] $Clean = $False,
+ [int] $DownloadRetries = 5,
+ [int] $RetryWaitTimeInSeconds = 30
+)
+
+. $PSScriptRoot\..\pipeline-logging-functions.ps1
+
+# Import common library modules
+Import-Module -Name (Join-Path $CommonLibraryDirectory "CommonLibrary.psm1")
+
+try {
+ # Define verbose switch if undefined
+ $Verbose = $VerbosePreference -Eq "Continue"
+
+ $Arch = CommonLibrary\Get-MachineArchitecture
+ $ToolOs = "win64"
+ if($Arch -Eq "x32") {
+ $ToolOs = "win32"
+ }
+ $ToolNameMoniker = "$ToolName-$Version-$ToolOs-$Arch"
+ $ToolInstallDirectory = Join-Path $InstallPath "$ToolName\$Version\"
+ $Uri = "$BaseUri/windows/$ToolName/$ToolNameMoniker.zip"
+ $ShimPath = Join-Path $InstallPath "$ToolName.exe"
+
+ if ($Clean) {
+ Write-Host "Cleaning $ToolInstallDirectory"
+ if (Test-Path $ToolInstallDirectory) {
+ Remove-Item $ToolInstallDirectory -Force -Recurse
+ }
+ Write-Host "Cleaning $ShimPath"
+ if (Test-Path $ShimPath) {
+ Remove-Item $ShimPath -Force
+ }
+ $ToolTempPath = CommonLibrary\Get-TempPathFilename -Path $Uri
+ Write-Host "Cleaning $ToolTempPath"
+ if (Test-Path $ToolTempPath) {
+ Remove-Item $ToolTempPath -Force
+ }
+ exit 0
+ }
+
+ # Install tool
+ if ((Test-Path $ToolInstallDirectory) -And (-Not $Force)) {
+ Write-Verbose "$ToolName ($Version) already exists, skipping install"
+ }
+ else {
+ $InstallStatus = CommonLibrary\DownloadAndExtract -Uri $Uri `
+ -InstallDirectory $ToolInstallDirectory `
+ -Force:$Force `
+ -DownloadRetries $DownloadRetries `
+ -RetryWaitTimeInSeconds $RetryWaitTimeInSeconds `
+ -Verbose:$Verbose
+
+ if ($InstallStatus -Eq $False) {
+ Write-PipelineTelemetryError "Installation failed" -Category "NativeToolsetBootstrapping"
+ exit 1
+ }
+ }
+
+ $ToolFilePath = Get-ChildItem $ToolInstallDirectory -Recurse -Filter "$ToolName.exe" | % { $_.FullName }
+ if (@($ToolFilePath).Length -Gt 1) {
+ Write-Error "There are multiple copies of $ToolName in $($ToolInstallDirectory): `n$(@($ToolFilePath | out-string))"
+ exit 1
+ } elseif (@($ToolFilePath).Length -Lt 1) {
+ Write-Host "$ToolName was not found in $ToolInstallDirectory."
+ exit 1
+ }
+
+ # Generate shim
+ # Always rewrite shims so that we are referencing the expected version
+ $GenerateShimStatus = CommonLibrary\New-ScriptShim -ShimName $ToolName `
+ -ShimDirectory $InstallPath `
+ -ToolFilePath "$ToolFilePath" `
+ -BaseUri $BaseUri `
+ -Force:$Force `
+ -Verbose:$Verbose
+
+ if ($GenerateShimStatus -Eq $False) {
+ Write-PipelineTelemetryError "Generate shim failed" -Category "NativeToolsetBootstrapping"
+ return 1
+ }
+
+ exit 0
+}
+catch {
+ Write-Host $_.ScriptStackTrace
+ Write-PipelineTelemetryError -Category "NativeToolsetBootstrapping" -Message $_
+ exit 1
+}
diff --git a/eng/common/pipeline-logging-functions.ps1 b/eng/common/pipeline-logging-functions.ps1
new file mode 100644
index 000000000..8e422c561
--- /dev/null
+++ b/eng/common/pipeline-logging-functions.ps1
@@ -0,0 +1,260 @@
+# Source for this file was taken from https://github.com/microsoft/azure-pipelines-task-lib/blob/11c9439d4af17e6475d9fe058e6b2e03914d17e6/powershell/VstsTaskSdk/LoggingCommandFunctions.ps1 and modified.
+
+# NOTE: You should not be calling these method directly as they are likely to change. Instead you should be calling the Write-Pipeline* functions defined in tools.ps1
+
+$script:loggingCommandPrefix = '##vso['
+$script:loggingCommandEscapeMappings = @( # TODO: WHAT ABOUT "="? WHAT ABOUT "%"?
+ New-Object psobject -Property @{ Token = ';' ; Replacement = '%3B' }
+ New-Object psobject -Property @{ Token = "`r" ; Replacement = '%0D' }
+ New-Object psobject -Property @{ Token = "`n" ; Replacement = '%0A' }
+ New-Object psobject -Property @{ Token = "]" ; Replacement = '%5D' }
+)
+# TODO: BUG: Escape % ???
+# TODO: Add test to verify don't need to escape "=".
+
+# Specify "-Force" to force pipeline formatted output even if "$ci" is false or not set
+function Write-PipelineTelemetryError {
+ [CmdletBinding()]
+ param(
+ [Parameter(Mandatory = $true)]
+ [string]$Category,
+ [Parameter(Mandatory = $true)]
+ [string]$Message,
+ [Parameter(Mandatory = $false)]
+ [string]$Type = 'error',
+ [string]$ErrCode,
+ [string]$SourcePath,
+ [string]$LineNumber,
+ [string]$ColumnNumber,
+ [switch]$AsOutput,
+ [switch]$Force)
+
+ $PSBoundParameters.Remove('Category') | Out-Null
+
+ if ($Force -Or ((Test-Path variable:ci) -And $ci)) {
+ $Message = "(NETCORE_ENGINEERING_TELEMETRY=$Category) $Message"
+ }
+ $PSBoundParameters.Remove('Message') | Out-Null
+ $PSBoundParameters.Add('Message', $Message)
+ Write-PipelineTaskError @PSBoundParameters
+}
+
+# Specify "-Force" to force pipeline formatted output even if "$ci" is false or not set
+function Write-PipelineTaskError {
+ [CmdletBinding()]
+ param(
+ [Parameter(Mandatory = $true)]
+ [string]$Message,
+ [Parameter(Mandatory = $false)]
+ [string]$Type = 'error',
+ [string]$ErrCode,
+ [string]$SourcePath,
+ [string]$LineNumber,
+ [string]$ColumnNumber,
+ [switch]$AsOutput,
+ [switch]$Force
+ )
+
+ if (!$Force -And (-Not (Test-Path variable:ci) -Or !$ci)) {
+ if ($Type -eq 'error') {
+ Write-Host $Message -ForegroundColor Red
+ return
+ }
+ elseif ($Type -eq 'warning') {
+ Write-Host $Message -ForegroundColor Yellow
+ return
+ }
+ }
+
+ if (($Type -ne 'error') -and ($Type -ne 'warning')) {
+ Write-Host $Message
+ return
+ }
+ $PSBoundParameters.Remove('Force') | Out-Null
+ if (-not $PSBoundParameters.ContainsKey('Type')) {
+ $PSBoundParameters.Add('Type', 'error')
+ }
+ Write-LogIssue @PSBoundParameters
+}
+
+function Write-PipelineSetVariable {
+ [CmdletBinding()]
+ param(
+ [Parameter(Mandatory = $true)]
+ [string]$Name,
+ [string]$Value,
+ [switch]$Secret,
+ [switch]$AsOutput,
+ [bool]$IsMultiJobVariable = $true)
+
+ if ((Test-Path variable:ci) -And $ci) {
+ Write-LoggingCommand -Area 'task' -Event 'setvariable' -Data $Value -Properties @{
+ 'variable' = $Name
+ 'isSecret' = $Secret
+ 'isOutput' = $IsMultiJobVariable
+ } -AsOutput:$AsOutput
+ }
+}
+
+function Write-PipelinePrependPath {
+ [CmdletBinding()]
+ param(
+ [Parameter(Mandatory = $true)]
+ [string]$Path,
+ [switch]$AsOutput)
+
+ if ((Test-Path variable:ci) -And $ci) {
+ Write-LoggingCommand -Area 'task' -Event 'prependpath' -Data $Path -AsOutput:$AsOutput
+ }
+}
+
+function Write-PipelineSetResult {
+ [CmdletBinding()]
+ param(
+ [ValidateSet("Succeeded", "SucceededWithIssues", "Failed", "Cancelled", "Skipped")]
+ [Parameter(Mandatory = $true)]
+ [string]$Result,
+ [string]$Message)
+ if ((Test-Path variable:ci) -And $ci) {
+ Write-LoggingCommand -Area 'task' -Event 'complete' -Data $Message -Properties @{
+ 'result' = $Result
+ }
+ }
+}
+
+<########################################
+# Private functions.
+########################################>
+function Format-LoggingCommandData {
+ [CmdletBinding()]
+ param([string]$Value, [switch]$Reverse)
+
+ if (!$Value) {
+ return ''
+ }
+
+ if (!$Reverse) {
+ foreach ($mapping in $script:loggingCommandEscapeMappings) {
+ $Value = $Value.Replace($mapping.Token, $mapping.Replacement)
+ }
+ }
+ else {
+ for ($i = $script:loggingCommandEscapeMappings.Length - 1 ; $i -ge 0 ; $i--) {
+ $mapping = $script:loggingCommandEscapeMappings[$i]
+ $Value = $Value.Replace($mapping.Replacement, $mapping.Token)
+ }
+ }
+
+ return $Value
+}
+
+function Format-LoggingCommand {
+ [CmdletBinding()]
+ param(
+ [Parameter(Mandatory = $true)]
+ [string]$Area,
+ [Parameter(Mandatory = $true)]
+ [string]$Event,
+ [string]$Data,
+ [hashtable]$Properties)
+
+ # Append the preamble.
+ [System.Text.StringBuilder]$sb = New-Object -TypeName System.Text.StringBuilder
+ $null = $sb.Append($script:loggingCommandPrefix).Append($Area).Append('.').Append($Event)
+
+ # Append the properties.
+ if ($Properties) {
+ $first = $true
+ foreach ($key in $Properties.Keys) {
+ [string]$value = Format-LoggingCommandData $Properties[$key]
+ if ($value) {
+ if ($first) {
+ $null = $sb.Append(' ')
+ $first = $false
+ }
+ else {
+ $null = $sb.Append(';')
+ }
+
+ $null = $sb.Append("$key=$value")
+ }
+ }
+ }
+
+ # Append the tail and output the value.
+ $Data = Format-LoggingCommandData $Data
+ $sb.Append(']').Append($Data).ToString()
+}
+
+function Write-LoggingCommand {
+ [CmdletBinding(DefaultParameterSetName = 'Parameters')]
+ param(
+ [Parameter(Mandatory = $true, ParameterSetName = 'Parameters')]
+ [string]$Area,
+ [Parameter(Mandatory = $true, ParameterSetName = 'Parameters')]
+ [string]$Event,
+ [Parameter(ParameterSetName = 'Parameters')]
+ [string]$Data,
+ [Parameter(ParameterSetName = 'Parameters')]
+ [hashtable]$Properties,
+ [Parameter(Mandatory = $true, ParameterSetName = 'Object')]
+ $Command,
+ [switch]$AsOutput)
+
+ if ($PSCmdlet.ParameterSetName -eq 'Object') {
+ Write-LoggingCommand -Area $Command.Area -Event $Command.Event -Data $Command.Data -Properties $Command.Properties -AsOutput:$AsOutput
+ return
+ }
+
+ $command = Format-LoggingCommand -Area $Area -Event $Event -Data $Data -Properties $Properties
+ if ($AsOutput) {
+ $command
+ }
+ else {
+ Write-Host $command
+ }
+}
+
+function Write-LogIssue {
+ [CmdletBinding()]
+ param(
+ [ValidateSet('warning', 'error')]
+ [Parameter(Mandatory = $true)]
+ [string]$Type,
+ [string]$Message,
+ [string]$ErrCode,
+ [string]$SourcePath,
+ [string]$LineNumber,
+ [string]$ColumnNumber,
+ [switch]$AsOutput)
+
+ $command = Format-LoggingCommand -Area 'task' -Event 'logissue' -Data $Message -Properties @{
+ 'type' = $Type
+ 'code' = $ErrCode
+ 'sourcepath' = $SourcePath
+ 'linenumber' = $LineNumber
+ 'columnnumber' = $ColumnNumber
+ }
+ if ($AsOutput) {
+ return $command
+ }
+
+ if ($Type -eq 'error') {
+ $foregroundColor = $host.PrivateData.ErrorForegroundColor
+ $backgroundColor = $host.PrivateData.ErrorBackgroundColor
+ if ($foregroundColor -isnot [System.ConsoleColor] -or $backgroundColor -isnot [System.ConsoleColor]) {
+ $foregroundColor = [System.ConsoleColor]::Red
+ $backgroundColor = [System.ConsoleColor]::Black
+ }
+ }
+ else {
+ $foregroundColor = $host.PrivateData.WarningForegroundColor
+ $backgroundColor = $host.PrivateData.WarningBackgroundColor
+ if ($foregroundColor -isnot [System.ConsoleColor] -or $backgroundColor -isnot [System.ConsoleColor]) {
+ $foregroundColor = [System.ConsoleColor]::Yellow
+ $backgroundColor = [System.ConsoleColor]::Black
+ }
+ }
+
+ Write-Host $command -ForegroundColor $foregroundColor -BackgroundColor $backgroundColor
+}
diff --git a/eng/common/pipeline-logging-functions.sh b/eng/common/pipeline-logging-functions.sh
new file mode 100644
index 000000000..6a0b2255e
--- /dev/null
+++ b/eng/common/pipeline-logging-functions.sh
@@ -0,0 +1,206 @@
+#!/usr/bin/env bash
+
+function Write-PipelineTelemetryError {
+ local telemetry_category=''
+ local force=false
+ local function_args=()
+ local message=''
+ while [[ $# -gt 0 ]]; do
+ opt="$(echo "${1/#--/-}" | tr "[:upper:]" "[:lower:]")"
+ case "$opt" in
+ -category|-c)
+ telemetry_category=$2
+ shift
+ ;;
+ -force|-f)
+ force=true
+ ;;
+ -*)
+ function_args+=("$1 $2")
+ shift
+ ;;
+ *)
+ message=$*
+ ;;
+ esac
+ shift
+ done
+
+ if [[ $force != true ]] && [[ "$ci" != true ]]; then
+ echo "$message" >&2
+ return
+ fi
+
+ if [[ $force == true ]]; then
+ function_args+=("-force")
+ fi
+ message="(NETCORE_ENGINEERING_TELEMETRY=$telemetry_category) $message"
+ function_args+=("$message")
+ Write-PipelineTaskError ${function_args[@]}
+}
+
+function Write-PipelineTaskError {
+ local message_type="error"
+ local sourcepath=''
+ local linenumber=''
+ local columnnumber=''
+ local error_code=''
+ local force=false
+
+ while [[ $# -gt 0 ]]; do
+ opt="$(echo "${1/#--/-}" | tr "[:upper:]" "[:lower:]")"
+ case "$opt" in
+ -type|-t)
+ message_type=$2
+ shift
+ ;;
+ -sourcepath|-s)
+ sourcepath=$2
+ shift
+ ;;
+ -linenumber|-ln)
+ linenumber=$2
+ shift
+ ;;
+ -columnnumber|-cn)
+ columnnumber=$2
+ shift
+ ;;
+ -errcode|-e)
+ error_code=$2
+ shift
+ ;;
+ -force|-f)
+ force=true
+ ;;
+ *)
+ break
+ ;;
+ esac
+
+ shift
+ done
+
+ if [[ $force != true ]] && [[ "$ci" != true ]]; then
+ echo "$@" >&2
+ return
+ fi
+
+ local message="##vso[task.logissue"
+
+ message="$message type=$message_type"
+
+ if [ -n "$sourcepath" ]; then
+ message="$message;sourcepath=$sourcepath"
+ fi
+
+ if [ -n "$linenumber" ]; then
+ message="$message;linenumber=$linenumber"
+ fi
+
+ if [ -n "$columnnumber" ]; then
+ message="$message;columnnumber=$columnnumber"
+ fi
+
+ if [ -n "$error_code" ]; then
+ message="$message;code=$error_code"
+ fi
+
+ message="$message]$*"
+ echo "$message"
+}
+
+function Write-PipelineSetVariable {
+ if [[ "$ci" != true ]]; then
+ return
+ fi
+
+ local name=''
+ local value=''
+ local secret=false
+ local as_output=false
+ local is_multi_job_variable=true
+
+ while [[ $# -gt 0 ]]; do
+ opt="$(echo "${1/#--/-}" | tr "[:upper:]" "[:lower:]")"
+ case "$opt" in
+ -name|-n)
+ name=$2
+ shift
+ ;;
+ -value|-v)
+ value=$2
+ shift
+ ;;
+ -secret|-s)
+ secret=true
+ ;;
+ -as_output|-a)
+ as_output=true
+ ;;
+ -is_multi_job_variable|-i)
+ is_multi_job_variable=$2
+ shift
+ ;;
+ esac
+ shift
+ done
+
+ value=${value/;/%3B}
+ value=${value/\\r/%0D}
+ value=${value/\\n/%0A}
+ value=${value/]/%5D}
+
+ local message="##vso[task.setvariable variable=$name;isSecret=$secret;isOutput=$is_multi_job_variable]$value"
+
+ if [[ "$as_output" == true ]]; then
+ $message
+ else
+ echo "$message"
+ fi
+}
+
+function Write-PipelinePrependPath {
+ local prepend_path=''
+
+ while [[ $# -gt 0 ]]; do
+ opt="$(echo "${1/#--/-}" | tr "[:upper:]" "[:lower:]")"
+ case "$opt" in
+ -path|-p)
+ prepend_path=$2
+ shift
+ ;;
+ esac
+ shift
+ done
+
+ export PATH="$prepend_path:$PATH"
+
+ if [[ "$ci" == true ]]; then
+ echo "##vso[task.prependpath]$prepend_path"
+ fi
+}
+
+function Write-PipelineSetResult {
+ local result=''
+ local message=''
+
+ while [[ $# -gt 0 ]]; do
+ opt="$(echo "${1/#--/-}" | tr "[:upper:]" "[:lower:]")"
+ case "$opt" in
+ -result|-r)
+ result=$2
+ shift
+ ;;
+ -message|-m)
+ message=$2
+ shift
+ ;;
+ esac
+ shift
+ done
+
+ if [[ "$ci" == true ]]; then
+ echo "##vso[task.complete result=$result;]$message"
+ fi
+}
diff --git a/eng/common/post-build/add-build-to-channel.ps1 b/eng/common/post-build/add-build-to-channel.ps1
new file mode 100644
index 000000000..de2d95792
--- /dev/null
+++ b/eng/common/post-build/add-build-to-channel.ps1
@@ -0,0 +1,48 @@
+param(
+ [Parameter(Mandatory=$true)][int] $BuildId,
+ [Parameter(Mandatory=$true)][int] $ChannelId,
+ [Parameter(Mandatory=$true)][string] $MaestroApiAccessToken,
+ [Parameter(Mandatory=$false)][string] $MaestroApiEndPoint = 'https://maestro-prod.westus2.cloudapp.azure.com',
+ [Parameter(Mandatory=$false)][string] $MaestroApiVersion = '2019-01-16'
+)
+
+try {
+ . $PSScriptRoot\post-build-utils.ps1
+
+ # Check that the channel we are going to promote the build to exist
+ $channelInfo = Get-MaestroChannel -ChannelId $ChannelId
+
+ if (!$channelInfo) {
+ Write-PipelineTelemetryCategory -Category 'PromoteBuild' -Message "Channel with BAR ID $ChannelId was not found in BAR!"
+ ExitWithExitCode 1
+ }
+
+ # Get info about which channel(s) the build has already been promoted to
+ $buildInfo = Get-MaestroBuild -BuildId $BuildId
+
+ if (!$buildInfo) {
+ Write-PipelineTelemetryError -Category 'PromoteBuild' -Message "Build with BAR ID $BuildId was not found in BAR!"
+ ExitWithExitCode 1
+ }
+
+ # Find whether the build is already assigned to the channel or not
+ if ($buildInfo.channels) {
+ foreach ($channel in $buildInfo.channels) {
+ if ($channel.Id -eq $ChannelId) {
+ Write-Host "The build with BAR ID $BuildId is already on channel $ChannelId!"
+ ExitWithExitCode 0
+ }
+ }
+ }
+
+ Write-Host "Promoting build '$BuildId' to channel '$ChannelId'."
+
+ Assign-BuildToChannel -BuildId $BuildId -ChannelId $ChannelId
+
+ Write-Host 'done.'
+}
+catch {
+ Write-Host $_
+ Write-PipelineTelemetryError -Category 'PromoteBuild' -Message "There was an error while trying to promote build '$BuildId' to channel '$ChannelId'"
+ ExitWithExitCode 1
+}
diff --git a/eng/common/post-build/check-channel-consistency.ps1 b/eng/common/post-build/check-channel-consistency.ps1
new file mode 100644
index 000000000..63f3464c9
--- /dev/null
+++ b/eng/common/post-build/check-channel-consistency.ps1
@@ -0,0 +1,40 @@
+param(
+ [Parameter(Mandatory=$true)][string] $PromoteToChannels, # List of channels that the build should be promoted to
+ [Parameter(Mandatory=$true)][array] $AvailableChannelIds # List of channel IDs available in the YAML implementation
+)
+
+try {
+ . $PSScriptRoot\post-build-utils.ps1
+
+ if ($PromoteToChannels -eq "") {
+ Write-PipelineTaskError -Type 'warning' -Message "This build won't publish assets as it's not configured to any Maestro channel. If that wasn't intended use Darc to configure a default channel using add-default-channel for this branch or to promote it to a channel using add-build-to-channel. See https://github.com/dotnet/arcade/blob/master/Documentation/Darc.md#assigning-an-individual-build-to-a-channel for more info."
+ ExitWithExitCode 0
+ }
+
+ # Check that every channel that Maestro told to promote the build to
+ # is available in YAML
+ $PromoteToChannelsIds = $PromoteToChannels -split "\D" | Where-Object { $_ }
+
+ $hasErrors = $false
+
+ foreach ($id in $PromoteToChannelsIds) {
+ if (($id -ne 0) -and ($id -notin $AvailableChannelIds)) {
+ Write-PipelineTaskError -Message "Channel $id is not present in the post-build YAML configuration! This is an error scenario. Please contact @dnceng."
+ $hasErrors = $true
+ }
+ }
+
+ # The `Write-PipelineTaskError` doesn't error the script and we might report several errors
+ # in the previous lines. The check below makes sure that we return an error state from the
+ # script if we reported any validation error
+ if ($hasErrors) {
+ ExitWithExitCode 1
+ }
+
+ Write-Host 'done.'
+}
+catch {
+ Write-Host $_
+ Write-PipelineTelemetryError -Category 'CheckChannelConsistency' -Message "There was an error while trying to check consistency of Maestro default channels for the build and post-build YAML configuration."
+ ExitWithExitCode 1
+}
diff --git a/eng/common/post-build/nuget-validation.ps1 b/eng/common/post-build/nuget-validation.ps1
new file mode 100644
index 000000000..dab3534ab
--- /dev/null
+++ b/eng/common/post-build/nuget-validation.ps1
@@ -0,0 +1,24 @@
+# This script validates NuGet package metadata information using this
+# tool: https://github.com/NuGet/NuGetGallery/tree/jver-verify/src/VerifyMicrosoftPackage
+
+param(
+ [Parameter(Mandatory=$true)][string] $PackagesPath, # Path to where the packages to be validated are
+ [Parameter(Mandatory=$true)][string] $ToolDestinationPath # Where the validation tool should be downloaded to
+)
+
+try {
+ . $PSScriptRoot\post-build-utils.ps1
+
+ $url = 'https://raw.githubusercontent.com/NuGet/NuGetGallery/3e25ad135146676bcab0050a516939d9958bfa5d/src/VerifyMicrosoftPackage/verify.ps1'
+
+ New-Item -ItemType 'directory' -Path ${ToolDestinationPath} -Force
+
+ Invoke-WebRequest $url -OutFile ${ToolDestinationPath}\verify.ps1
+
+ & ${ToolDestinationPath}\verify.ps1 ${PackagesPath}\*.nupkg
+}
+catch {
+ Write-Host $_.ScriptStackTrace
+ Write-PipelineTelemetryError -Category 'NuGetValidation' -Message $_
+ ExitWithExitCode 1
+}
diff --git a/eng/common/post-build/post-build-utils.ps1 b/eng/common/post-build/post-build-utils.ps1
new file mode 100644
index 000000000..534f6988d
--- /dev/null
+++ b/eng/common/post-build/post-build-utils.ps1
@@ -0,0 +1,91 @@
+# Most of the functions in this file require the variables `MaestroApiEndPoint`,
+# `MaestroApiVersion` and `MaestroApiAccessToken` to be globally available.
+
+$ErrorActionPreference = 'Stop'
+Set-StrictMode -Version 2.0
+
+# `tools.ps1` checks $ci to perform some actions. Since the post-build
+# scripts don't necessarily execute in the same agent that run the
+# build.ps1/sh script this variable isn't automatically set.
+$ci = $true
+$disableConfigureToolsetImport = $true
+. $PSScriptRoot\..\tools.ps1
+
+function Create-MaestroApiRequestHeaders([string]$ContentType = 'application/json') {
+ Validate-MaestroVars
+
+ $headers = New-Object 'System.Collections.Generic.Dictionary[[String],[String]]'
+ $headers.Add('Accept', $ContentType)
+ $headers.Add('Authorization',"Bearer $MaestroApiAccessToken")
+ return $headers
+}
+
+function Get-MaestroChannel([int]$ChannelId) {
+ Validate-MaestroVars
+
+ $apiHeaders = Create-MaestroApiRequestHeaders
+ $apiEndpoint = "$MaestroApiEndPoint/api/channels/${ChannelId}?api-version=$MaestroApiVersion"
+
+ $result = try { Invoke-WebRequest -Method Get -Uri $apiEndpoint -Headers $apiHeaders | ConvertFrom-Json } catch { Write-Host "Error: $_" }
+ return $result
+}
+
+function Get-MaestroBuild([int]$BuildId) {
+ Validate-MaestroVars
+
+ $apiHeaders = Create-MaestroApiRequestHeaders -AuthToken $MaestroApiAccessToken
+ $apiEndpoint = "$MaestroApiEndPoint/api/builds/${BuildId}?api-version=$MaestroApiVersion"
+
+ $result = try { return Invoke-WebRequest -Method Get -Uri $apiEndpoint -Headers $apiHeaders | ConvertFrom-Json } catch { Write-Host "Error: $_" }
+ return $result
+}
+
+function Get-MaestroSubscriptions([string]$SourceRepository, [int]$ChannelId) {
+ Validate-MaestroVars
+
+ $SourceRepository = [System.Web.HttpUtility]::UrlEncode($SourceRepository)
+ $apiHeaders = Create-MaestroApiRequestHeaders -AuthToken $MaestroApiAccessToken
+ $apiEndpoint = "$MaestroApiEndPoint/api/subscriptions?sourceRepository=$SourceRepository&channelId=$ChannelId&api-version=$MaestroApiVersion"
+
+ $result = try { Invoke-WebRequest -Method Get -Uri $apiEndpoint -Headers $apiHeaders | ConvertFrom-Json } catch { Write-Host "Error: $_" }
+ return $result
+}
+
+function Assign-BuildToChannel([int]$BuildId, [int]$ChannelId) {
+ Validate-MaestroVars
+
+ $apiHeaders = Create-MaestroApiRequestHeaders -AuthToken $MaestroApiAccessToken
+ $apiEndpoint = "$MaestroApiEndPoint/api/channels/${ChannelId}/builds/${BuildId}?api-version=$MaestroApiVersion"
+ Invoke-WebRequest -Method Post -Uri $apiEndpoint -Headers $apiHeaders | Out-Null
+}
+
+function Trigger-Subscription([string]$SubscriptionId) {
+ Validate-MaestroVars
+
+ $apiHeaders = Create-MaestroApiRequestHeaders -AuthToken $MaestroApiAccessToken
+ $apiEndpoint = "$MaestroApiEndPoint/api/subscriptions/$SubscriptionId/trigger?api-version=$MaestroApiVersion"
+ Invoke-WebRequest -Uri $apiEndpoint -Headers $apiHeaders -Method Post | Out-Null
+}
+
+function Validate-MaestroVars {
+ try {
+ Get-Variable MaestroApiEndPoint | Out-Null
+ Get-Variable MaestroApiVersion | Out-Null
+ Get-Variable MaestroApiAccessToken | Out-Null
+
+ if (!($MaestroApiEndPoint -Match '^http[s]?://maestro-(int|prod).westus2.cloudapp.azure.com$')) {
+ Write-PipelineTelemetryError -Category 'MaestroVars' -Message "MaestroApiEndPoint is not a valid Maestro URL. '$MaestroApiEndPoint'"
+ ExitWithExitCode 1
+ }
+
+ if (!($MaestroApiVersion -Match '^[0-9]{4}-[0-9]{2}-[0-9]{2}$')) {
+ Write-PipelineTelemetryError -Category 'MaestroVars' -Message "MaestroApiVersion does not match a version string in the format yyyy-MM-DD. '$MaestroApiVersion'"
+ ExitWithExitCode 1
+ }
+ }
+ catch {
+ Write-PipelineTelemetryError -Category 'MaestroVars' -Message 'Error: Variables `MaestroApiEndPoint`, `MaestroApiVersion` and `MaestroApiAccessToken` are required while using this script.'
+ Write-Host $_
+ ExitWithExitCode 1
+ }
+}
diff --git a/eng/common/post-build/publish-using-darc.ps1 b/eng/common/post-build/publish-using-darc.ps1
new file mode 100644
index 000000000..2427ca6b6
--- /dev/null
+++ b/eng/common/post-build/publish-using-darc.ps1
@@ -0,0 +1,80 @@
+param(
+ [Parameter(Mandatory=$true)][int] $BuildId,
+ [Parameter(Mandatory=$true)][int] $PublishingInfraVersion,
+ [Parameter(Mandatory=$true)][string] $AzdoToken,
+ [Parameter(Mandatory=$true)][string] $MaestroToken,
+ [Parameter(Mandatory=$false)][string] $MaestroApiEndPoint = 'https://maestro-prod.westus2.cloudapp.azure.com',
+ [Parameter(Mandatory=$true)][string] $WaitPublishingFinish,
+ [Parameter(Mandatory=$false)][string] $EnableSourceLinkValidation,
+ [Parameter(Mandatory=$false)][string] $EnableSigningValidation,
+ [Parameter(Mandatory=$false)][string] $EnableNugetValidation,
+ [Parameter(Mandatory=$false)][string] $PublishInstallersAndChecksums,
+ [Parameter(Mandatory=$false)][string] $ArtifactsPublishingAdditionalParameters,
+ [Parameter(Mandatory=$false)][string] $SymbolPublishingAdditionalParameters,
+ [Parameter(Mandatory=$false)][string] $SigningValidationAdditionalParameters
+)
+
+try {
+ . $PSScriptRoot\post-build-utils.ps1
+
+ $darc = Get-Darc
+
+ $optionalParams = [System.Collections.ArrayList]::new()
+
+ if ("" -ne $ArtifactsPublishingAdditionalParameters) {
+ $optionalParams.Add("--artifact-publishing-parameters") | Out-Null
+ $optionalParams.Add($ArtifactsPublishingAdditionalParameters) | Out-Null
+ }
+
+ if ("" -ne $SymbolPublishingAdditionalParameters) {
+ $optionalParams.Add("--symbol-publishing-parameters") | Out-Null
+ $optionalParams.Add($SymbolPublishingAdditionalParameters) | Out-Null
+ }
+
+ if ("false" -eq $WaitPublishingFinish) {
+ $optionalParams.Add("--no-wait") | Out-Null
+ }
+
+ if ("false" -ne $PublishInstallersAndChecksums) {
+ $optionalParams.Add("--publish-installers-and-checksums") | Out-Null
+ }
+
+ if ("true" -eq $EnableNugetValidation) {
+ $optionalParams.Add("--validate-nuget") | Out-Null
+ }
+
+ if ("true" -eq $EnableSourceLinkValidation) {
+ $optionalParams.Add("--validate-sourcelinkchecksums") | Out-Null
+ }
+
+ if ("true" -eq $EnableSigningValidation) {
+ $optionalParams.Add("--validate-signingchecksums") | Out-Null
+
+ if ("" -ne $SigningValidationAdditionalParameters) {
+ $optionalParams.Add("--signing-validation-parameters") | Out-Null
+ $optionalParams.Add($SigningValidationAdditionalParameters) | Out-Null
+ }
+ }
+
+ & $darc add-build-to-channel `
+ --id $buildId `
+ --publishing-infra-version $PublishingInfraVersion `
+ --default-channels `
+ --source-branch main `
+ --azdev-pat $AzdoToken `
+ --bar-uri $MaestroApiEndPoint `
+ --password $MaestroToken `
+ @optionalParams
+
+ if ($LastExitCode -ne 0) {
+ Write-Host "Problems using Darc to promote build ${buildId} to default channels. Stopping execution..."
+ exit 1
+ }
+
+ Write-Host 'done.'
+}
+catch {
+ Write-Host $_
+ Write-PipelineTelemetryError -Category 'PromoteBuild' -Message "There was an error while trying to publish build '$BuildId' to default channels."
+ ExitWithExitCode 1
+}
diff --git a/eng/common/post-build/sourcelink-validation.ps1 b/eng/common/post-build/sourcelink-validation.ps1
new file mode 100644
index 000000000..85c898617
--- /dev/null
+++ b/eng/common/post-build/sourcelink-validation.ps1
@@ -0,0 +1,303 @@
+param(
+ [Parameter(Mandatory=$true)][string] $InputPath, # Full path to directory where Symbols.NuGet packages to be checked are stored
+ [Parameter(Mandatory=$true)][string] $ExtractPath, # Full path to directory where the packages will be extracted during validation
+ [Parameter(Mandatory=$false)][string] $GHRepoName, # GitHub name of the repo including the Org. E.g., dotnet/arcade
+ [Parameter(Mandatory=$false)][string] $GHCommit, # GitHub commit SHA used to build the packages
+ [Parameter(Mandatory=$true)][string] $SourcelinkCliVersion # Version of SourceLink CLI to use
+)
+
+. $PSScriptRoot\post-build-utils.ps1
+
+# Cache/HashMap (File -> Exist flag) used to consult whether a file exist
+# in the repository at a specific commit point. This is populated by inserting
+# all files present in the repo at a specific commit point.
+$global:RepoFiles = @{}
+
+# Maximum number of jobs to run in parallel
+$MaxParallelJobs = 16
+
+$MaxRetries = 5
+
+# Wait time between check for system load
+$SecondsBetweenLoadChecks = 10
+
+$ValidatePackage = {
+ param(
+ [string] $PackagePath # Full path to a Symbols.NuGet package
+ )
+
+ . $using:PSScriptRoot\..\tools.ps1
+
+ # Ensure input file exist
+ if (!(Test-Path $PackagePath)) {
+ Write-Host "Input file does not exist: $PackagePath"
+ return [pscustomobject]@{
+ result = 1
+ packagePath = $PackagePath
+ }
+ }
+
+ # Extensions for which we'll look for SourceLink information
+ # For now we'll only care about Portable & Embedded PDBs
+ $RelevantExtensions = @('.dll', '.exe', '.pdb')
+
+ Write-Host -NoNewLine 'Validating ' ([System.IO.Path]::GetFileName($PackagePath)) '...'
+
+ $PackageId = [System.IO.Path]::GetFileNameWithoutExtension($PackagePath)
+ $ExtractPath = Join-Path -Path $using:ExtractPath -ChildPath $PackageId
+ $FailedFiles = 0
+
+ Add-Type -AssemblyName System.IO.Compression.FileSystem
+
+ [System.IO.Directory]::CreateDirectory($ExtractPath) | Out-Null
+
+ try {
+ $zip = [System.IO.Compression.ZipFile]::OpenRead($PackagePath)
+
+ $zip.Entries |
+ Where-Object {$RelevantExtensions -contains [System.IO.Path]::GetExtension($_.Name)} |
+ ForEach-Object {
+ $FileName = $_.FullName
+ $Extension = [System.IO.Path]::GetExtension($_.Name)
+ $FakeName = -Join((New-Guid), $Extension)
+ $TargetFile = Join-Path -Path $ExtractPath -ChildPath $FakeName
+
+ # We ignore resource DLLs
+ if ($FileName.EndsWith('.resources.dll')) {
+ return [pscustomobject]@{
+ result = 0
+ packagePath = $PackagePath
+ }
+ }
+
+ [System.IO.Compression.ZipFileExtensions]::ExtractToFile($_, $TargetFile, $true)
+
+ $ValidateFile = {
+ param(
+ [string] $FullPath, # Full path to the module that has to be checked
+ [string] $RealPath,
+ [ref] $FailedFiles
+ )
+
+ $sourcelinkExe = "$env:USERPROFILE\.dotnet\tools"
+ $sourcelinkExe = Resolve-Path "$sourcelinkExe\sourcelink.exe"
+ $SourceLinkInfos = & $sourcelinkExe print-urls $FullPath | Out-String
+
+ if ($LASTEXITCODE -eq 0 -and -not ([string]::IsNullOrEmpty($SourceLinkInfos))) {
+ $NumFailedLinks = 0
+
+ # We only care about Http addresses
+ $Matches = (Select-String '(http[s]?)(:\/\/)([^\s,]+)' -Input $SourceLinkInfos -AllMatches).Matches
+
+ if ($Matches.Count -ne 0) {
+ $Matches.Value |
+ ForEach-Object {
+ $Link = $_
+ $CommitUrl = "https://raw.githubusercontent.com/${using:GHRepoName}/${using:GHCommit}/"
+
+ $FilePath = $Link.Replace($CommitUrl, "")
+ $Status = 200
+ $Cache = $using:RepoFiles
+
+ $totalRetries = 0
+
+ while ($totalRetries -lt $using:MaxRetries) {
+ if ( !($Cache.ContainsKey($FilePath)) ) {
+ try {
+ $Uri = $Link -as [System.URI]
+
+ # Only GitHub links are valid
+ if ($Uri.AbsoluteURI -ne $null -and ($Uri.Host -match 'github' -or $Uri.Host -match 'githubusercontent')) {
+ $Status = (Invoke-WebRequest -Uri $Link -UseBasicParsing -Method HEAD -TimeoutSec 5).StatusCode
+ }
+ else {
+ # If it's not a github link, we want to break out of the loop and not retry.
+ $Status = 0
+ $totalRetries = $using:MaxRetries
+ }
+ }
+ catch {
+ Write-Host $_
+ $Status = 0
+ }
+ }
+
+ if ($Status -ne 200) {
+ $totalRetries++
+
+ if ($totalRetries -ge $using:MaxRetries) {
+ if ($NumFailedLinks -eq 0) {
+ if ($FailedFiles.Value -eq 0) {
+ Write-Host
+ }
+
+ Write-Host "`tFile $RealPath has broken links:"
+ }
+
+ Write-Host "`t`tFailed to retrieve $Link"
+
+ $NumFailedLinks++
+ }
+ }
+ else {
+ break
+ }
+ }
+ }
+ }
+
+ if ($NumFailedLinks -ne 0) {
+ $FailedFiles.value++
+ $global:LASTEXITCODE = 1
+ }
+ }
+ }
+
+ &$ValidateFile $TargetFile $FileName ([ref]$FailedFiles)
+ }
+ }
+ catch {
+ Write-Host $_
+ }
+ finally {
+ $zip.Dispose()
+ }
+
+ if ($FailedFiles -eq 0) {
+ Write-Host 'Passed.'
+ return [pscustomobject]@{
+ result = 0
+ packagePath = $PackagePath
+ }
+ }
+ else {
+ Write-PipelineTelemetryError -Category 'SourceLink' -Message "$PackagePath has broken SourceLink links."
+ return [pscustomobject]@{
+ result = 1
+ packagePath = $PackagePath
+ }
+ }
+}
+
+function CheckJobResult(
+ $result,
+ $packagePath,
+ [ref]$ValidationFailures,
+ [switch]$logErrors) {
+ if ($result -ne '0') {
+ if ($logErrors) {
+ Write-PipelineTelemetryError -Category 'SourceLink' -Message "$packagePath has broken SourceLink links."
+ }
+ $ValidationFailures.Value++
+ }
+}
+
+function ValidateSourceLinkLinks {
+ if ($GHRepoName -ne '' -and !($GHRepoName -Match '^[^\s\/]+/[^\s\/]+$')) {
+ if (!($GHRepoName -Match '^[^\s-]+-[^\s]+$')) {
+ Write-PipelineTelemetryError -Category 'SourceLink' -Message "GHRepoName should be in the format / or -. '$GHRepoName'"
+ ExitWithExitCode 1
+ }
+ else {
+ $GHRepoName = $GHRepoName -replace '^([^\s-]+)-([^\s]+)$', '$1/$2';
+ }
+ }
+
+ if ($GHCommit -ne '' -and !($GHCommit -Match '^[0-9a-fA-F]{40}$')) {
+ Write-PipelineTelemetryError -Category 'SourceLink' -Message "GHCommit should be a 40 chars hexadecimal string. '$GHCommit'"
+ ExitWithExitCode 1
+ }
+
+ if ($GHRepoName -ne '' -and $GHCommit -ne '') {
+ $RepoTreeURL = -Join('http://api.github.com/repos/', $GHRepoName, '/git/trees/', $GHCommit, '?recursive=1')
+ $CodeExtensions = @('.cs', '.vb', '.fs', '.fsi', '.fsx', '.fsscript')
+
+ try {
+ # Retrieve the list of files in the repo at that particular commit point and store them in the RepoFiles hash
+ $Data = Invoke-WebRequest $RepoTreeURL -UseBasicParsing | ConvertFrom-Json | Select-Object -ExpandProperty tree
+
+ foreach ($file in $Data) {
+ $Extension = [System.IO.Path]::GetExtension($file.path)
+
+ if ($CodeExtensions.Contains($Extension)) {
+ $RepoFiles[$file.path] = 1
+ }
+ }
+ }
+ catch {
+ Write-Host "Problems downloading the list of files from the repo. Url used: $RepoTreeURL . Execution will proceed without caching."
+ }
+ }
+ elseif ($GHRepoName -ne '' -or $GHCommit -ne '') {
+ Write-Host 'For using the http caching mechanism both GHRepoName and GHCommit should be informed.'
+ }
+
+ if (Test-Path $ExtractPath) {
+ Remove-Item $ExtractPath -Force -Recurse -ErrorAction SilentlyContinue
+ }
+
+ $ValidationFailures = 0
+
+ # Process each NuGet package in parallel
+ Get-ChildItem "$InputPath\*.symbols.nupkg" |
+ ForEach-Object {
+ Write-Host "Starting $($_.FullName)"
+ Start-Job -ScriptBlock $ValidatePackage -ArgumentList $_.FullName | Out-Null
+ $NumJobs = @(Get-Job -State 'Running').Count
+
+ while ($NumJobs -ge $MaxParallelJobs) {
+ Write-Host "There are $NumJobs validation jobs running right now. Waiting $SecondsBetweenLoadChecks seconds to check again."
+ sleep $SecondsBetweenLoadChecks
+ $NumJobs = @(Get-Job -State 'Running').Count
+ }
+
+ foreach ($Job in @(Get-Job -State 'Completed')) {
+ $jobResult = Wait-Job -Id $Job.Id | Receive-Job
+ CheckJobResult $jobResult.result $jobResult.packagePath ([ref]$ValidationFailures) -LogErrors
+ Remove-Job -Id $Job.Id
+ }
+ }
+
+ foreach ($Job in @(Get-Job)) {
+ $jobResult = Wait-Job -Id $Job.Id | Receive-Job
+ CheckJobResult $jobResult.result $jobResult.packagePath ([ref]$ValidationFailures)
+ Remove-Job -Id $Job.Id
+ }
+ if ($ValidationFailures -gt 0) {
+ Write-PipelineTelemetryError -Category 'SourceLink' -Message "$ValidationFailures package(s) failed validation."
+ ExitWithExitCode 1
+ }
+}
+
+function InstallSourcelinkCli {
+ $sourcelinkCliPackageName = 'sourcelink'
+
+ $dotnetRoot = InitializeDotNetCli -install:$true
+ $dotnet = "$dotnetRoot\dotnet.exe"
+ $toolList = & "$dotnet" tool list --global
+
+ if (($toolList -like "*$sourcelinkCliPackageName*") -and ($toolList -like "*$sourcelinkCliVersion*")) {
+ Write-Host "SourceLink CLI version $sourcelinkCliVersion is already installed."
+ }
+ else {
+ Write-Host "Installing SourceLink CLI version $sourcelinkCliVersion..."
+ Write-Host 'You may need to restart your command window if this is the first dotnet tool you have installed.'
+ & "$dotnet" tool install $sourcelinkCliPackageName --version $sourcelinkCliVersion --verbosity "minimal" --global
+ }
+}
+
+try {
+ InstallSourcelinkCli
+
+ foreach ($Job in @(Get-Job)) {
+ Remove-Job -Id $Job.Id
+ }
+
+ ValidateSourceLinkLinks
+}
+catch {
+ Write-Host $_.Exception
+ Write-Host $_.ScriptStackTrace
+ Write-PipelineTelemetryError -Category 'SourceLink' -Message $_
+ ExitWithExitCode 1
+}
diff --git a/eng/common/post-build/symbols-validation.ps1 b/eng/common/post-build/symbols-validation.ps1
new file mode 100644
index 000000000..a5af041ba
--- /dev/null
+++ b/eng/common/post-build/symbols-validation.ps1
@@ -0,0 +1,316 @@
+param(
+ [Parameter(Mandatory = $true)][string] $InputPath, # Full path to directory where NuGet packages to be checked are stored
+ [Parameter(Mandatory = $true)][string] $ExtractPath, # Full path to directory where the packages will be extracted during validation
+ [Parameter(Mandatory = $true)][string] $DotnetSymbolVersion, # Version of dotnet symbol to use
+ [Parameter(Mandatory = $false)][switch] $CheckForWindowsPdbs, # If we should check for the existence of windows pdbs in addition to portable PDBs
+ [Parameter(Mandatory = $false)][switch] $ContinueOnError, # If we should keep checking symbols after an error
+ [Parameter(Mandatory = $false)][switch] $Clean # Clean extracted symbols directory after checking symbols
+)
+
+# Maximum number of jobs to run in parallel
+$MaxParallelJobs = 16
+
+# Max number of retries
+$MaxRetry = 5
+
+# Wait time between check for system load
+$SecondsBetweenLoadChecks = 10
+
+# Set error codes
+Set-Variable -Name "ERROR_BADEXTRACT" -Option Constant -Value -1
+Set-Variable -Name "ERROR_FILEDOESNOTEXIST" -Option Constant -Value -2
+
+$WindowsPdbVerificationParam = ""
+if ($CheckForWindowsPdbs) {
+ $WindowsPdbVerificationParam = "--windows-pdbs"
+}
+
+$CountMissingSymbols = {
+ param(
+ [string] $PackagePath, # Path to a NuGet package
+ [string] $WindowsPdbVerificationParam # If we should check for the existence of windows pdbs in addition to portable PDBs
+ )
+
+ . $using:PSScriptRoot\..\tools.ps1
+
+ Add-Type -AssemblyName System.IO.Compression.FileSystem
+
+ Write-Host "Validating $PackagePath "
+
+ # Ensure input file exist
+ if (!(Test-Path $PackagePath)) {
+ Write-PipelineTaskError "Input file does not exist: $PackagePath"
+ return [pscustomobject]@{
+ result = $using:ERROR_FILEDOESNOTEXIST
+ packagePath = $PackagePath
+ }
+ }
+
+ # Extensions for which we'll look for symbols
+ $RelevantExtensions = @('.dll', '.exe', '.so', '.dylib')
+
+ # How many files are missing symbol information
+ $MissingSymbols = 0
+
+ $PackageId = [System.IO.Path]::GetFileNameWithoutExtension($PackagePath)
+ $PackageGuid = New-Guid
+ $ExtractPath = Join-Path -Path $using:ExtractPath -ChildPath $PackageGuid
+ $SymbolsPath = Join-Path -Path $ExtractPath -ChildPath 'Symbols'
+
+ try {
+ [System.IO.Compression.ZipFile]::ExtractToDirectory($PackagePath, $ExtractPath)
+ }
+ catch {
+ Write-Host "Something went wrong extracting $PackagePath"
+ Write-Host $_
+ return [pscustomobject]@{
+ result = $using:ERROR_BADEXTRACT
+ packagePath = $PackagePath
+ }
+ }
+
+ Get-ChildItem -Recurse $ExtractPath |
+ Where-Object { $RelevantExtensions -contains $_.Extension } |
+ ForEach-Object {
+ $FileName = $_.FullName
+ if ($FileName -Match '\\ref\\') {
+ Write-Host "`t Ignoring reference assembly file " $FileName
+ return
+ }
+
+ $FirstMatchingSymbolDescriptionOrDefault = {
+ param(
+ [string] $FullPath, # Full path to the module that has to be checked
+ [string] $TargetServerParam, # Parameter to pass to `Symbol Tool` indicating the server to lookup for symbols
+ [string] $WindowsPdbVerificationParam, # Parameter to pass to potential check for windows-pdbs.
+ [string] $SymbolsPath
+ )
+
+ $FileName = [System.IO.Path]::GetFileName($FullPath)
+ $Extension = [System.IO.Path]::GetExtension($FullPath)
+
+ # Those below are potential symbol files that the `dotnet symbol` might
+ # return. Which one will be returned depend on the type of file we are
+ # checking and which type of file was uploaded.
+
+ # The file itself is returned
+ $SymbolPath = $SymbolsPath + '\' + $FileName
+
+ # PDB file for the module
+ $PdbPath = $SymbolPath.Replace($Extension, '.pdb')
+
+ # PDB file for R2R module (created by crossgen)
+ $NGenPdb = $SymbolPath.Replace($Extension, '.ni.pdb')
+
+ # DBG file for a .so library
+ $SODbg = $SymbolPath.Replace($Extension, '.so.dbg')
+
+ # DWARF file for a .dylib
+ $DylibDwarf = $SymbolPath.Replace($Extension, '.dylib.dwarf')
+
+ $dotnetSymbolExe = "$env:USERPROFILE\.dotnet\tools"
+ $dotnetSymbolExe = Resolve-Path "$dotnetSymbolExe\dotnet-symbol.exe"
+
+ $totalRetries = 0
+
+ while ($totalRetries -lt $using:MaxRetry) {
+
+ # Save the output and get diagnostic output
+ $output = & $dotnetSymbolExe --symbols --modules $WindowsPdbVerificationParam $TargetServerParam $FullPath -o $SymbolsPath --diagnostics | Out-String
+
+ if (Test-Path $PdbPath) {
+ return 'PDB'
+ }
+ elseif (Test-Path $NGenPdb) {
+ return 'NGen PDB'
+ }
+ elseif (Test-Path $SODbg) {
+ return 'DBG for SO'
+ }
+ elseif (Test-Path $DylibDwarf) {
+ return 'Dwarf for Dylib'
+ }
+ elseif (Test-Path $SymbolPath) {
+ return 'Module'
+ }
+ else
+ {
+ $totalRetries++
+ }
+ }
+
+ return $null
+ }
+
+ $FileGuid = New-Guid
+ $ExpandedSymbolsPath = Join-Path -Path $SymbolsPath -ChildPath $FileGuid
+
+ $SymbolsOnMSDL = & $FirstMatchingSymbolDescriptionOrDefault `
+ -FullPath $FileName `
+ -TargetServerParam '--microsoft-symbol-server' `
+ -SymbolsPath "$ExpandedSymbolsPath-msdl" `
+ -WindowsPdbVerificationParam $WindowsPdbVerificationParam
+ $SymbolsOnSymWeb = & $FirstMatchingSymbolDescriptionOrDefault `
+ -FullPath $FileName `
+ -TargetServerParam '--internal-server' `
+ -SymbolsPath "$ExpandedSymbolsPath-symweb" `
+ -WindowsPdbVerificationParam $WindowsPdbVerificationParam
+
+ Write-Host -NoNewLine "`t Checking file " $FileName "... "
+
+ if ($SymbolsOnMSDL -ne $null -and $SymbolsOnSymWeb -ne $null) {
+ Write-Host "Symbols found on MSDL ($SymbolsOnMSDL) and SymWeb ($SymbolsOnSymWeb)"
+ }
+ else {
+ $MissingSymbols++
+
+ if ($SymbolsOnMSDL -eq $null -and $SymbolsOnSymWeb -eq $null) {
+ Write-Host 'No symbols found on MSDL or SymWeb!'
+ }
+ else {
+ if ($SymbolsOnMSDL -eq $null) {
+ Write-Host 'No symbols found on MSDL!'
+ }
+ else {
+ Write-Host 'No symbols found on SymWeb!'
+ }
+ }
+ }
+ }
+
+ if ($using:Clean) {
+ Remove-Item $ExtractPath -Recurse -Force
+ }
+
+ Pop-Location
+
+ return [pscustomobject]@{
+ result = $MissingSymbols
+ packagePath = $PackagePath
+ }
+}
+
+function CheckJobResult(
+ $result,
+ $packagePath,
+ [ref]$DupedSymbols,
+ [ref]$TotalFailures) {
+ if ($result -eq $ERROR_BADEXTRACT) {
+ Write-PipelineTelemetryError -Category 'CheckSymbols' -Message "$packagePath has duplicated symbol files"
+ $DupedSymbols.Value++
+ }
+ elseif ($result -eq $ERROR_FILEDOESNOTEXIST) {
+ Write-PipelineTelemetryError -Category 'CheckSymbols' -Message "$packagePath does not exist"
+ $TotalFailures.Value++
+ }
+ elseif ($result -gt '0') {
+ Write-PipelineTelemetryError -Category 'CheckSymbols' -Message "Missing symbols for $result modules in the package $packagePath"
+ $TotalFailures.Value++
+ }
+ else {
+ Write-Host "All symbols verified for package $packagePath"
+ }
+}
+
+function CheckSymbolsAvailable {
+ if (Test-Path $ExtractPath) {
+ Remove-Item $ExtractPath -Force -Recurse -ErrorAction SilentlyContinue
+ }
+
+ $TotalPackages = 0
+ $TotalFailures = 0
+ $DupedSymbols = 0
+
+ Get-ChildItem "$InputPath\*.nupkg" |
+ ForEach-Object {
+ $FileName = $_.Name
+ $FullName = $_.FullName
+
+ # These packages from Arcade-Services include some native libraries that
+ # our current symbol uploader can't handle. Below is a workaround until
+ # we get issue: https://github.com/dotnet/arcade/issues/2457 sorted.
+ if ($FileName -Match 'Microsoft\.DotNet\.Darc\.') {
+ Write-Host "Ignoring Arcade-services file: $FileName"
+ Write-Host
+ return
+ }
+ elseif ($FileName -Match 'Microsoft\.DotNet\.Maestro\.Tasks\.') {
+ Write-Host "Ignoring Arcade-services file: $FileName"
+ Write-Host
+ return
+ }
+
+ $TotalPackages++
+
+ Start-Job -ScriptBlock $CountMissingSymbols -ArgumentList @($FullName,$WindowsPdbVerificationParam) | Out-Null
+
+ $NumJobs = @(Get-Job -State 'Running').Count
+
+ while ($NumJobs -ge $MaxParallelJobs) {
+ Write-Host "There are $NumJobs validation jobs running right now. Waiting $SecondsBetweenLoadChecks seconds to check again."
+ sleep $SecondsBetweenLoadChecks
+ $NumJobs = @(Get-Job -State 'Running').Count
+ }
+
+ foreach ($Job in @(Get-Job -State 'Completed')) {
+ $jobResult = Wait-Job -Id $Job.Id | Receive-Job
+ CheckJobResult $jobResult.result $jobResult.packagePath ([ref]$DupedSymbols) ([ref]$TotalFailures)
+ Remove-Job -Id $Job.Id
+ }
+ Write-Host
+ }
+
+ foreach ($Job in @(Get-Job)) {
+ $jobResult = Wait-Job -Id $Job.Id | Receive-Job
+ CheckJobResult $jobResult.result $jobResult.packagePath ([ref]$DupedSymbols) ([ref]$TotalFailures)
+ }
+
+ if ($TotalFailures -gt 0 -or $DupedSymbols -gt 0) {
+ if ($TotalFailures -gt 0) {
+ Write-PipelineTelemetryError -Category 'CheckSymbols' -Message "Symbols missing for $TotalFailures/$TotalPackages packages"
+ }
+
+ if ($DupedSymbols -gt 0) {
+ Write-PipelineTelemetryError -Category 'CheckSymbols' -Message "$DupedSymbols/$TotalPackages packages had duplicated symbol files and could not be extracted"
+ }
+
+ ExitWithExitCode 1
+ }
+ else {
+ Write-Host "All symbols validated!"
+ }
+}
+
+function InstallDotnetSymbol {
+ $dotnetSymbolPackageName = 'dotnet-symbol'
+
+ $dotnetRoot = InitializeDotNetCli -install:$true
+ $dotnet = "$dotnetRoot\dotnet.exe"
+ $toolList = & "$dotnet" tool list --global
+
+ if (($toolList -like "*$dotnetSymbolPackageName*") -and ($toolList -like "*$dotnetSymbolVersion*")) {
+ Write-Host "dotnet-symbol version $dotnetSymbolVersion is already installed."
+ }
+ else {
+ Write-Host "Installing dotnet-symbol version $dotnetSymbolVersion..."
+ Write-Host 'You may need to restart your command window if this is the first dotnet tool you have installed.'
+ & "$dotnet" tool install $dotnetSymbolPackageName --version $dotnetSymbolVersion --verbosity "minimal" --global
+ }
+}
+
+try {
+ . $PSScriptRoot\post-build-utils.ps1
+
+ InstallDotnetSymbol
+
+ foreach ($Job in @(Get-Job)) {
+ Remove-Job -Id $Job.Id
+ }
+
+ CheckSymbolsAvailable
+}
+catch {
+ Write-Host $_.ScriptStackTrace
+ Write-PipelineTelemetryError -Category 'CheckSymbols' -Message $_
+ ExitWithExitCode 1
+}
diff --git a/eng/common/post-build/trigger-subscriptions.ps1 b/eng/common/post-build/trigger-subscriptions.ps1
new file mode 100644
index 000000000..55dea518a
--- /dev/null
+++ b/eng/common/post-build/trigger-subscriptions.ps1
@@ -0,0 +1,64 @@
+param(
+ [Parameter(Mandatory=$true)][string] $SourceRepo,
+ [Parameter(Mandatory=$true)][int] $ChannelId,
+ [Parameter(Mandatory=$true)][string] $MaestroApiAccessToken,
+ [Parameter(Mandatory=$false)][string] $MaestroApiEndPoint = 'https://maestro-prod.westus2.cloudapp.azure.com',
+ [Parameter(Mandatory=$false)][string] $MaestroApiVersion = '2019-01-16'
+)
+
+try {
+ . $PSScriptRoot\post-build-utils.ps1
+
+ # Get all the $SourceRepo subscriptions
+ $normalizedSourceRepo = $SourceRepo.Replace('dnceng@', '')
+ $subscriptions = Get-MaestroSubscriptions -SourceRepository $normalizedSourceRepo -ChannelId $ChannelId
+
+ if (!$subscriptions) {
+ Write-PipelineTelemetryError -Category 'TriggerSubscriptions' -Message "No subscriptions found for source repo '$normalizedSourceRepo' in channel '$ChannelId'"
+ ExitWithExitCode 0
+ }
+
+ $subscriptionsToTrigger = New-Object System.Collections.Generic.List[string]
+ $failedTriggeredSubscription = $false
+
+ # Get all enabled subscriptions that need dependency flow on 'everyBuild'
+ foreach ($subscription in $subscriptions) {
+ if ($subscription.enabled -and $subscription.policy.updateFrequency -like 'everyBuild' -and $subscription.channel.id -eq $ChannelId) {
+ Write-Host "Should trigger this subscription: ${$subscription.id}"
+ [void]$subscriptionsToTrigger.Add($subscription.id)
+ }
+ }
+
+ foreach ($subscriptionToTrigger in $subscriptionsToTrigger) {
+ try {
+ Write-Host "Triggering subscription '$subscriptionToTrigger'."
+
+ Trigger-Subscription -SubscriptionId $subscriptionToTrigger
+
+ Write-Host 'done.'
+ }
+ catch
+ {
+ Write-Host "There was an error while triggering subscription '$subscriptionToTrigger'"
+ Write-Host $_
+ Write-Host $_.ScriptStackTrace
+ $failedTriggeredSubscription = $true
+ }
+ }
+
+ if ($subscriptionsToTrigger.Count -eq 0) {
+ Write-Host "No subscription matched source repo '$normalizedSourceRepo' and channel ID '$ChannelId'."
+ }
+ elseif ($failedTriggeredSubscription) {
+ Write-PipelineTelemetryError -Category 'TriggerSubscriptions' -Message 'At least one subscription failed to be triggered...'
+ ExitWithExitCode 1
+ }
+ else {
+ Write-Host 'All subscriptions were triggered successfully!'
+ }
+}
+catch {
+ Write-Host $_.ScriptStackTrace
+ Write-PipelineTelemetryError -Category 'TriggerSubscriptions' -Message $_
+ ExitWithExitCode 1
+}
diff --git a/eng/common/sdk-task.ps1 b/eng/common/sdk-task.ps1
new file mode 100644
index 000000000..b1bca63ab
--- /dev/null
+++ b/eng/common/sdk-task.ps1
@@ -0,0 +1,97 @@
+[CmdletBinding(PositionalBinding=$false)]
+Param(
+ [string] $configuration = 'Debug',
+ [string] $task,
+ [string] $verbosity = 'minimal',
+ [string] $msbuildEngine = $null,
+ [switch] $restore,
+ [switch] $prepareMachine,
+ [switch] $help,
+ [Parameter(ValueFromRemainingArguments=$true)][String[]]$properties
+)
+
+$ci = $true
+$binaryLog = $true
+$warnAsError = $true
+
+. $PSScriptRoot\tools.ps1
+
+function Print-Usage() {
+ Write-Host "Common settings:"
+ Write-Host " -task Name of Arcade task (name of a project in SdkTasks directory of the Arcade SDK package)"
+ Write-Host " -restore Restore dependencies"
+ Write-Host " -verbosity Msbuild verbosity: q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic]"
+ Write-Host " -help Print help and exit"
+ Write-Host ""
+
+ Write-Host "Advanced settings:"
+ Write-Host " -prepareMachine Prepare machine for CI run"
+ Write-Host " -msbuildEngine Msbuild engine to use to run build ('dotnet', 'vs', or unspecified)."
+ Write-Host ""
+ Write-Host "Command line arguments not listed above are passed thru to msbuild."
+}
+
+function Build([string]$target) {
+ $logSuffix = if ($target -eq 'Execute') { '' } else { ".$target" }
+ $log = Join-Path $LogDir "$task$logSuffix.binlog"
+ $outputPath = Join-Path $ToolsetDir "$task\"
+
+ MSBuild $taskProject `
+ /bl:$log `
+ /t:$target `
+ /p:Configuration=$configuration `
+ /p:RepoRoot=$RepoRoot `
+ /p:BaseIntermediateOutputPath=$outputPath `
+ /v:$verbosity `
+ @properties
+}
+
+try {
+ if ($help -or (($null -ne $properties) -and ($properties.Contains('/help') -or $properties.Contains('/?')))) {
+ Print-Usage
+ exit 0
+ }
+
+ if ($task -eq "") {
+ Write-PipelineTelemetryError -Category 'Build' -Message "Missing required parameter '-task '"
+ Print-Usage
+ ExitWithExitCode 1
+ }
+
+ if( $msbuildEngine -eq "vs") {
+ # Ensure desktop MSBuild is available for sdk tasks.
+ if( -not ($GlobalJson.tools.PSObject.Properties.Name -contains "vs" )) {
+ $GlobalJson.tools | Add-Member -Name "vs" -Value (ConvertFrom-Json "{ `"version`": `"16.5`" }") -MemberType NoteProperty
+ }
+ if( -not ($GlobalJson.tools.PSObject.Properties.Name -match "xcopy-msbuild" )) {
+ $GlobalJson.tools | Add-Member -Name "xcopy-msbuild" -Value "16.10.0-preview2" -MemberType NoteProperty
+ }
+ if ($GlobalJson.tools."xcopy-msbuild".Trim() -ine "none") {
+ $xcopyMSBuildToolsFolder = InitializeXCopyMSBuild $GlobalJson.tools."xcopy-msbuild" -install $true
+ }
+ if ($xcopyMSBuildToolsFolder -eq $null) {
+ throw 'Unable to get xcopy downloadable version of msbuild'
+ }
+
+ $global:_MSBuildExe = "$($xcopyMSBuildToolsFolder)\MSBuild\Current\Bin\MSBuild.exe"
+ }
+
+ $taskProject = GetSdkTaskProject $task
+ if (!(Test-Path $taskProject)) {
+ Write-PipelineTelemetryError -Category 'Build' -Message "Unknown task: $task"
+ ExitWithExitCode 1
+ }
+
+ if ($restore) {
+ Build 'Restore'
+ }
+
+ Build 'Execute'
+}
+catch {
+ Write-Host $_.ScriptStackTrace
+ Write-PipelineTelemetryError -Category 'Build' -Message $_
+ ExitWithExitCode 1
+}
+
+ExitWithExitCode 0
diff --git a/eng/common/sdl/NuGet.config b/eng/common/sdl/NuGet.config
new file mode 100644
index 000000000..0c5451c11
--- /dev/null
+++ b/eng/common/sdl/NuGet.config
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/eng/common/sdl/configure-sdl-tool.ps1 b/eng/common/sdl/configure-sdl-tool.ps1
new file mode 100644
index 000000000..4999c3070
--- /dev/null
+++ b/eng/common/sdl/configure-sdl-tool.ps1
@@ -0,0 +1,109 @@
+Param(
+ [string] $GuardianCliLocation,
+ [string] $WorkingDirectory,
+ [string] $TargetDirectory,
+ [string] $GdnFolder,
+ # The list of Guardian tools to configure. For each object in the array:
+ # - If the item is a [hashtable], it must contain these entries:
+ # - Name = The tool name as Guardian knows it.
+ # - Scenario = (Optional) Scenario-specific name for this configuration entry. It must be unique
+ # among all tool entries with the same Name.
+ # - Args = (Optional) Array of Guardian tool configuration args, like '@("Target > C:\temp")'
+ # - If the item is a [string] $v, it is treated as '@{ Name="$v" }'
+ [object[]] $ToolsList,
+ [string] $GuardianLoggerLevel='Standard',
+ # Optional: Additional params to add to any tool using CredScan.
+ [string[]] $CrScanAdditionalRunConfigParams,
+ # Optional: Additional params to add to any tool using PoliCheck.
+ [string[]] $PoliCheckAdditionalRunConfigParams
+)
+
+$ErrorActionPreference = 'Stop'
+Set-StrictMode -Version 2.0
+$disableConfigureToolsetImport = $true
+$global:LASTEXITCODE = 0
+
+try {
+ # `tools.ps1` checks $ci to perform some actions. Since the SDL
+ # scripts don't necessarily execute in the same agent that run the
+ # build.ps1/sh script this variable isn't automatically set.
+ $ci = $true
+ . $PSScriptRoot\..\tools.ps1
+
+ # Normalize tools list: all in [hashtable] form with defined values for each key.
+ $ToolsList = $ToolsList |
+ ForEach-Object {
+ if ($_ -is [string]) {
+ $_ = @{ Name = $_ }
+ }
+
+ if (-not ($_['Scenario'])) { $_.Scenario = "" }
+ if (-not ($_['Args'])) { $_.Args = @() }
+ $_
+ }
+
+ Write-Host "List of tools to configure:"
+ $ToolsList | ForEach-Object { $_ | Out-String | Write-Host }
+
+ # We store config files in the r directory of .gdn
+ $gdnConfigPath = Join-Path $GdnFolder 'r'
+ $ValidPath = Test-Path $GuardianCliLocation
+
+ if ($ValidPath -eq $False)
+ {
+ Write-PipelineTelemetryError -Force -Category 'Sdl' -Message "Invalid Guardian CLI Location."
+ ExitWithExitCode 1
+ }
+
+ foreach ($tool in $ToolsList) {
+ # Put together the name and scenario to make a unique key.
+ $toolConfigName = $tool.Name
+ if ($tool.Scenario) {
+ $toolConfigName += "_" + $tool.Scenario
+ }
+
+ Write-Host "=== Configuring $toolConfigName..."
+
+ $gdnConfigFile = Join-Path $gdnConfigPath "$toolConfigName-configure.gdnconfig"
+
+ # For some tools, add default and automatic args.
+ if ($tool.Name -eq 'credscan') {
+ if ($targetDirectory) {
+ $tool.Args += "TargetDirectory < $TargetDirectory"
+ }
+ $tool.Args += "OutputType < pre"
+ $tool.Args += $CrScanAdditionalRunConfigParams
+ } elseif ($tool.Name -eq 'policheck') {
+ if ($targetDirectory) {
+ $tool.Args += "Target < $TargetDirectory"
+ }
+ $tool.Args += $PoliCheckAdditionalRunConfigParams
+ }
+
+ # Create variable pointing to the args array directly so we can use splat syntax later.
+ $toolArgs = $tool.Args
+
+ # Configure the tool. If args array is provided or the current tool has some default arguments
+ # defined, add "--args" and splat each element on the end. Arg format is "{Arg id} < {Value}",
+ # one per parameter. Doc page for "guardian configure":
+ # https://dev.azure.com/securitytools/SecurityIntegration/_wiki/wikis/Guardian/1395/configure
+ Exec-BlockVerbosely {
+ & $GuardianCliLocation configure `
+ --working-directory $WorkingDirectory `
+ --tool $tool.Name `
+ --output-path $gdnConfigFile `
+ --logger-level $GuardianLoggerLevel `
+ --noninteractive `
+ --force `
+ $(if ($toolArgs) { "--args" }) @toolArgs
+ Exit-IfNZEC "Sdl"
+ }
+
+ Write-Host "Created '$toolConfigName' configuration file: $gdnConfigFile"
+ }
+}
+catch {
+ Write-Host $_.ScriptStackTrace
+ Write-PipelineTelemetryError -Force -Category 'Sdl' -Message $_
+ ExitWithExitCode 1
+}
diff --git a/eng/common/sdl/execute-all-sdl-tools.ps1 b/eng/common/sdl/execute-all-sdl-tools.ps1
new file mode 100644
index 000000000..1157151f4
--- /dev/null
+++ b/eng/common/sdl/execute-all-sdl-tools.ps1
@@ -0,0 +1,163 @@
+Param(
+ [string] $GuardianPackageName, # Required: the name of guardian CLI package (not needed if GuardianCliLocation is specified)
+ [string] $NugetPackageDirectory, # Required: directory where NuGet packages are installed (not needed if GuardianCliLocation is specified)
+ [string] $GuardianCliLocation, # Optional: Direct location of Guardian CLI executable if GuardianPackageName & NugetPackageDirectory are not specified
+ [string] $Repository=$env:BUILD_REPOSITORY_NAME, # Required: the name of the repository (e.g. dotnet/arcade)
+ [string] $BranchName=$env:BUILD_SOURCEBRANCH, # Optional: name of branch or version of gdn settings; defaults to master
+ [string] $SourceDirectory=$env:BUILD_SOURCESDIRECTORY, # Required: the directory where source files are located
+ [string] $ArtifactsDirectory = (Join-Path $env:BUILD_ARTIFACTSTAGINGDIRECTORY ('artifacts')), # Required: the directory where build artifacts are located
+ [string] $AzureDevOpsAccessToken, # Required: access token for dnceng; should be provided via KeyVault
+
+ # Optional: list of SDL tools to run on source code. See 'configure-sdl-tool.ps1' for tools list
+ # format.
+ [object[]] $SourceToolsList,
+ # Optional: list of SDL tools to run on built artifacts. See 'configure-sdl-tool.ps1' for tools
+ # list format.
+ [object[]] $ArtifactToolsList,
+ # Optional: list of SDL tools to run without automatically specifying a target directory. See
+ # 'configure-sdl-tool.ps1' for tools list format.
+ [object[]] $CustomToolsList,
+
+ [bool] $TsaPublish=$False, # Optional: true will publish results to TSA; only set to true after onboarding to TSA; TSA is the automated framework used to upload test results as bugs.
+ [string] $TsaBranchName=$env:BUILD_SOURCEBRANCH, # Optional: required for TSA publish; defaults to $(Build.SourceBranchName); TSA is the automated framework used to upload test results as bugs.
+ [string] $TsaRepositoryName=$env:BUILD_REPOSITORY_NAME, # Optional: TSA repository name; will be generated automatically if not submitted; TSA is the automated framework used to upload test results as bugs.
+ [string] $BuildNumber=$env:BUILD_BUILDNUMBER, # Optional: required for TSA publish; defaults to $(Build.BuildNumber)
+ [bool] $UpdateBaseline=$False, # Optional: if true, will update the baseline in the repository; should only be run after fixing any issues which need to be fixed
+ [bool] $TsaOnboard=$False, # Optional: if true, will onboard the repository to TSA; should only be run once; TSA is the automated framework used to upload test results as bugs.
+ [string] $TsaInstanceUrl, # Optional: only needed if TsaOnboard or TsaPublish is true; the instance-url registered with TSA; TSA is the automated framework used to upload test results as bugs.
+ [string] $TsaCodebaseName, # Optional: only needed if TsaOnboard or TsaPublish is true; the name of the codebase registered with TSA; TSA is the automated framework used to upload test results as bugs.
+ [string] $TsaProjectName, # Optional: only needed if TsaOnboard or TsaPublish is true; the name of the project registered with TSA; TSA is the automated framework used to upload test results as bugs.
+ [string] $TsaNotificationEmail, # Optional: only needed if TsaOnboard is true; the email(s) which will receive notifications of TSA bug filings (e.g. alias@microsoft.com); TSA is the automated framework used to upload test results as bugs.
+ [string] $TsaCodebaseAdmin, # Optional: only needed if TsaOnboard is true; the aliases which are admins of the TSA codebase (e.g. DOMAIN\alias); TSA is the automated framework used to upload test results as bugs.
+ [string] $TsaBugAreaPath, # Optional: only needed if TsaOnboard is true; the area path where TSA will file bugs in AzDO; TSA is the automated framework used to upload test results as bugs.
+ [string] $TsaIterationPath, # Optional: only needed if TsaOnboard is true; the iteration path where TSA will file bugs in AzDO; TSA is the automated framework used to upload test results as bugs.
+ [string] $GuardianLoggerLevel='Standard', # Optional: the logger level for the Guardian CLI; options are Trace, Verbose, Standard, Warning, and Error
+ [string[]] $CrScanAdditionalRunConfigParams, # Optional: Additional Params to custom build a CredScan run config in the format @("xyz:abc","sdf:1")
+ [string[]] $PoliCheckAdditionalRunConfigParams, # Optional: Additional Params to custom build a Policheck run config in the format @("xyz:abc","sdf:1")
+ [bool] $BreakOnFailure=$False # Optional: Fail the build if there were errors during the run
+)
+
+try {
+ $ErrorActionPreference = 'Stop'
+ Set-StrictMode -Version 2.0
+ $disableConfigureToolsetImport = $true
+ $global:LASTEXITCODE = 0
+
+ # `tools.ps1` checks $ci to perform some actions. Since the SDL
+ # scripts don't necessarily execute in the same agent that run the
+ # build.ps1/sh script this variable isn't automatically set.
+ $ci = $true
+ . $PSScriptRoot\..\tools.ps1
+
+ #Replace repo names to the format of org/repo
+ if (!($Repository.contains('/'))) {
+ $RepoName = $Repository -replace '(.*?)-(.*)', '$1/$2';
+ }
+ else{
+ $RepoName = $Repository;
+ }
+
+ if ($GuardianPackageName) {
+ $guardianCliLocation = Join-Path $NugetPackageDirectory (Join-Path $GuardianPackageName (Join-Path 'tools' 'guardian.cmd'))
+ } else {
+ $guardianCliLocation = $GuardianCliLocation
+ }
+
+ $workingDirectory = (Split-Path $SourceDirectory -Parent)
+ $ValidPath = Test-Path $guardianCliLocation
+
+ if ($ValidPath -eq $False)
+ {
+ Write-PipelineTelemetryError -Force -Category 'Sdl' -Message 'Invalid Guardian CLI Location.'
+ ExitWithExitCode 1
+ }
+
+ Exec-BlockVerbosely {
+ & $(Join-Path $PSScriptRoot 'init-sdl.ps1') -GuardianCliLocation $guardianCliLocation -Repository $RepoName -BranchName $BranchName -WorkingDirectory $workingDirectory -AzureDevOpsAccessToken $AzureDevOpsAccessToken -GuardianLoggerLevel $GuardianLoggerLevel
+ }
+ $gdnFolder = Join-Path $workingDirectory '.gdn'
+
+ if ($TsaOnboard) {
+ if ($TsaCodebaseName -and $TsaNotificationEmail -and $TsaCodebaseAdmin -and $TsaBugAreaPath) {
+ Exec-BlockVerbosely {
+ & $guardianCliLocation tsa-onboard --codebase-name "$TsaCodebaseName" --notification-alias "$TsaNotificationEmail" --codebase-admin "$TsaCodebaseAdmin" --instance-url "$TsaInstanceUrl" --project-name "$TsaProjectName" --area-path "$TsaBugAreaPath" --iteration-path "$TsaIterationPath" --working-directory $workingDirectory --logger-level $GuardianLoggerLevel
+ }
+ if ($LASTEXITCODE -ne 0) {
+ Write-PipelineTelemetryError -Force -Category 'Sdl' -Message "Guardian tsa-onboard failed with exit code $LASTEXITCODE."
+ ExitWithExitCode $LASTEXITCODE
+ }
+ } else {
+ Write-PipelineTelemetryError -Force -Category 'Sdl' -Message 'Could not onboard to TSA -- not all required values ($TsaCodebaseName, $TsaNotificationEmail, $TsaCodebaseAdmin, $TsaBugAreaPath) were specified.'
+ ExitWithExitCode 1
+ }
+ }
+
+ # Configure a list of tools with a default target directory. Populates the ".gdn/r" directory.
+ function Configure-ToolsList([object[]] $tools, [string] $targetDirectory) {
+ if ($tools -and $tools.Count -gt 0) {
+ Exec-BlockVerbosely {
+ & $(Join-Path $PSScriptRoot 'configure-sdl-tool.ps1') `
+ -GuardianCliLocation $guardianCliLocation `
+ -WorkingDirectory $workingDirectory `
+ -TargetDirectory $targetDirectory `
+ -GdnFolder $gdnFolder `
+ -ToolsList $tools `
+ -AzureDevOpsAccessToken $AzureDevOpsAccessToken `
+ -GuardianLoggerLevel $GuardianLoggerLevel `
+ -CrScanAdditionalRunConfigParams $CrScanAdditionalRunConfigParams `
+ -PoliCheckAdditionalRunConfigParams $PoliCheckAdditionalRunConfigParams
+ if ($BreakOnFailure) {
+ Exit-IfNZEC "Sdl"
+ }
+ }
+ }
+ }
+
+ # Configure Artifact and Source tools with default Target directories.
+ Configure-ToolsList $ArtifactToolsList $ArtifactsDirectory
+ Configure-ToolsList $SourceToolsList $SourceDirectory
+ # Configure custom tools with no default Target directory.
+ Configure-ToolsList $CustomToolsList $null
+
+ # At this point, all tools are configured in the ".gdn" directory. Run them all in a single call.
+ # (If we used "run" multiple times, each run would overwrite data from earlier runs.)
+ Exec-BlockVerbosely {
+ & $(Join-Path $PSScriptRoot 'run-sdl.ps1') `
+ -GuardianCliLocation $guardianCliLocation `
+ -WorkingDirectory $workingDirectory `
+ -UpdateBaseline $UpdateBaseline `
+ -GdnFolder $gdnFolder
+ }
+
+ if ($TsaPublish) {
+ if ($TsaBranchName -and $BuildNumber) {
+ if (-not $TsaRepositoryName) {
+ $TsaRepositoryName = "$($Repository)-$($BranchName)"
+ }
+ Exec-BlockVerbosely {
+ & $guardianCliLocation tsa-publish --all-tools --repository-name "$TsaRepositoryName" --branch-name "$TsaBranchName" --build-number "$BuildNumber" --onboard $True --codebase-name "$TsaCodebaseName" --notification-alias "$TsaNotificationEmail" --codebase-admin "$TsaCodebaseAdmin" --instance-url "$TsaInstanceUrl" --project-name "$TsaProjectName" --area-path "$TsaBugAreaPath" --iteration-path "$TsaIterationPath" --working-directory $workingDirectory --logger-level $GuardianLoggerLevel
+ }
+ if ($LASTEXITCODE -ne 0) {
+ Write-PipelineTelemetryError -Force -Category 'Sdl' -Message "Guardian tsa-publish failed with exit code $LASTEXITCODE."
+ ExitWithExitCode $LASTEXITCODE
+ }
+ } else {
+ Write-PipelineTelemetryError -Force -Category 'Sdl' -Message 'Could not publish to TSA -- not all required values ($TsaBranchName, $BuildNumber) were specified.'
+ ExitWithExitCode 1
+ }
+ }
+
+ if ($BreakOnFailure) {
+ Write-Host "Failing the build in case of breaking results..."
+ Exec-BlockVerbosely {
+ & $guardianCliLocation break --working-directory $workingDirectory --logger-level $GuardianLoggerLevel
+ }
+ } else {
+ Write-Host "Letting the build pass even if there were breaking results..."
+ }
+}
+catch {
+ Write-Host $_.ScriptStackTrace
+ Write-PipelineTelemetryError -Force -Category 'Sdl' -Message $_
+ exit 1
+}
diff --git a/eng/common/sdl/extract-artifact-archives.ps1 b/eng/common/sdl/extract-artifact-archives.ps1
new file mode 100644
index 000000000..68da4fbf2
--- /dev/null
+++ b/eng/common/sdl/extract-artifact-archives.ps1
@@ -0,0 +1,63 @@
+# This script looks for each archive file in a directory and extracts it into the target directory.
+# For example, the file "$InputPath/bin.tar.gz" extracts to "$ExtractPath/bin.tar.gz.extracted/**".
+# Uses the "tar" utility added to Windows 10 / Windows 2019 that supports tar.gz and zip.
+param(
+ # Full path to directory where archives are stored.
+ [Parameter(Mandatory=$true)][string] $InputPath,
+ # Full path to directory to extract archives into. May be the same as $InputPath.
+ [Parameter(Mandatory=$true)][string] $ExtractPath
+)
+
+$ErrorActionPreference = 'Stop'
+Set-StrictMode -Version 2.0
+
+$disableConfigureToolsetImport = $true
+
+try {
+ # `tools.ps1` checks $ci to perform some actions. Since the SDL
+ # scripts don't necessarily execute in the same agent that run the
+ # build.ps1/sh script this variable isn't automatically set.
+ $ci = $true
+ . $PSScriptRoot\..\tools.ps1
+
+ Measure-Command {
+ $jobs = @()
+
+ # Find archive files for non-Windows and Windows builds.
+ $archiveFiles = @(
+ Get-ChildItem (Join-Path $InputPath "*.tar.gz")
+ Get-ChildItem (Join-Path $InputPath "*.zip")
+ )
+
+ foreach ($targzFile in $archiveFiles) {
+ $jobs += Start-Job -ScriptBlock {
+ $file = $using:targzFile
+ $fileName = [System.IO.Path]::GetFileName($file)
+ $extractDir = Join-Path $using:ExtractPath "$fileName.extracted"
+
+ New-Item $extractDir -ItemType Directory -Force | Out-Null
+
+ Write-Host "Extracting '$file' to '$extractDir'..."
+
+ # Pipe errors to stdout to prevent PowerShell detecting them and quitting the job early.
+ # This type of quit skips the catch, so we wouldn't be able to tell which file triggered the
+ # error. Save output so it can be stored in the exception string along with context.
+ $output = tar -xf $file -C $extractDir 2>&1
+ # Handle NZEC manually rather than using Exit-IfNZEC: we are in a background job, so we
+ # don't have access to the outer scope.
+ if ($LASTEXITCODE -ne 0) {
+ throw "Error extracting '$file': non-zero exit code ($LASTEXITCODE). Output: '$output'"
+ }
+
+ Write-Host "Extracted to $extractDir"
+ }
+ }
+
+ Receive-Job $jobs -Wait
+ }
+}
+catch {
+ Write-Host $_
+ Write-PipelineTelemetryError -Force -Category 'Sdl' -Message $_
+ ExitWithExitCode 1
+}
diff --git a/eng/common/sdl/extract-artifact-packages.ps1 b/eng/common/sdl/extract-artifact-packages.ps1
new file mode 100644
index 000000000..7f28d9c59
--- /dev/null
+++ b/eng/common/sdl/extract-artifact-packages.ps1
@@ -0,0 +1,80 @@
+param(
+ [Parameter(Mandatory=$true)][string] $InputPath, # Full path to directory where artifact packages are stored
+ [Parameter(Mandatory=$true)][string] $ExtractPath # Full path to directory where the packages will be extracted
+)
+
+$ErrorActionPreference = 'Stop'
+Set-StrictMode -Version 2.0
+
+$disableConfigureToolsetImport = $true
+
+function ExtractArtifacts {
+ if (!(Test-Path $InputPath)) {
+ Write-Host "Input Path does not exist: $InputPath"
+ ExitWithExitCode 0
+ }
+ $Jobs = @()
+ Get-ChildItem "$InputPath\*.nupkg" |
+ ForEach-Object {
+ $Jobs += Start-Job -ScriptBlock $ExtractPackage -ArgumentList $_.FullName
+ }
+
+ foreach ($Job in $Jobs) {
+ Wait-Job -Id $Job.Id | Receive-Job
+ }
+}
+
+try {
+ # `tools.ps1` checks $ci to perform some actions. Since the SDL
+ # scripts don't necessarily execute in the same agent that run the
+ # build.ps1/sh script this variable isn't automatically set.
+ $ci = $true
+ . $PSScriptRoot\..\tools.ps1
+
+ $ExtractPackage = {
+ param(
+ [string] $PackagePath # Full path to a NuGet package
+ )
+
+ if (!(Test-Path $PackagePath)) {
+ Write-PipelineTelemetryError -Category 'Build' -Message "Input file does not exist: $PackagePath"
+ ExitWithExitCode 1
+ }
+
+ $RelevantExtensions = @('.dll', '.exe', '.pdb')
+ Write-Host -NoNewLine 'Extracting ' ([System.IO.Path]::GetFileName($PackagePath)) '...'
+
+ $PackageId = [System.IO.Path]::GetFileNameWithoutExtension($PackagePath)
+ $ExtractPath = Join-Path -Path $using:ExtractPath -ChildPath $PackageId
+
+ Add-Type -AssemblyName System.IO.Compression.FileSystem
+
+ [System.IO.Directory]::CreateDirectory($ExtractPath);
+
+ try {
+ $zip = [System.IO.Compression.ZipFile]::OpenRead($PackagePath)
+
+ $zip.Entries |
+ Where-Object {$RelevantExtensions -contains [System.IO.Path]::GetExtension($_.Name)} |
+ ForEach-Object {
+ $TargetFile = Join-Path -Path $ExtractPath -ChildPath $_.Name
+
+ [System.IO.Compression.ZipFileExtensions]::ExtractToFile($_, $TargetFile, $true)
+ }
+ }
+ catch {
+ Write-Host $_
+ Write-PipelineTelemetryError -Force -Category 'Sdl' -Message $_
+ ExitWithExitCode 1
+ }
+ finally {
+ $zip.Dispose()
+ }
+ }
+ Measure-Command { ExtractArtifacts }
+}
+catch {
+ Write-Host $_
+ Write-PipelineTelemetryError -Force -Category 'Sdl' -Message $_
+ ExitWithExitCode 1
+}
diff --git a/eng/common/sdl/init-sdl.ps1 b/eng/common/sdl/init-sdl.ps1
new file mode 100644
index 000000000..3ac1d92b3
--- /dev/null
+++ b/eng/common/sdl/init-sdl.ps1
@@ -0,0 +1,55 @@
+Param(
+ [string] $GuardianCliLocation,
+ [string] $Repository,
+ [string] $BranchName='master',
+ [string] $WorkingDirectory,
+ [string] $AzureDevOpsAccessToken,
+ [string] $GuardianLoggerLevel='Standard'
+)
+
+$ErrorActionPreference = 'Stop'
+Set-StrictMode -Version 2.0
+$disableConfigureToolsetImport = $true
+$global:LASTEXITCODE = 0
+
+# `tools.ps1` checks $ci to perform some actions. Since the SDL
+# scripts don't necessarily execute in the same agent that run the
+# build.ps1/sh script this variable isn't automatically set.
+$ci = $true
+. $PSScriptRoot\..\tools.ps1
+
+# Don't display the console progress UI - it's a huge perf hit
+$ProgressPreference = 'SilentlyContinue'
+
+# Construct basic auth from AzDO access token; construct URI to the repository's gdn folder stored in that repository; construct location of zip file
+$encodedPat = [Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$AzureDevOpsAccessToken"))
+$escapedRepository = [Uri]::EscapeDataString("/$Repository/$BranchName/.gdn")
+$uri = "https://dev.azure.com/dnceng/internal/_apis/git/repositories/sdl-tool-cfg/Items?path=$escapedRepository&versionDescriptor[versionOptions]=0&`$format=zip&api-version=5.0"
+$zipFile = "$WorkingDirectory/gdn.zip"
+
+Add-Type -AssemblyName System.IO.Compression.FileSystem
+$gdnFolder = (Join-Path $WorkingDirectory '.gdn')
+
+try {
+ # if the folder does not exist, we'll do a guardian init and push it to the remote repository
+ Write-Host 'Initializing Guardian...'
+ Write-Host "$GuardianCliLocation init --working-directory $WorkingDirectory --logger-level $GuardianLoggerLevel"
+ & $GuardianCliLocation init --working-directory $WorkingDirectory --logger-level $GuardianLoggerLevel
+ if ($LASTEXITCODE -ne 0) {
+ Write-PipelineTelemetryError -Force -Category 'Build' -Message "Guardian init failed with exit code $LASTEXITCODE."
+ ExitWithExitCode $LASTEXITCODE
+ }
+ # We create the mainbaseline so it can be edited later
+ Write-Host "$GuardianCliLocation baseline --working-directory $WorkingDirectory --name mainbaseline"
+ & $GuardianCliLocation baseline --working-directory $WorkingDirectory --name mainbaseline
+ if ($LASTEXITCODE -ne 0) {
+ Write-PipelineTelemetryError -Force -Category 'Build' -Message "Guardian baseline failed with exit code $LASTEXITCODE."
+ ExitWithExitCode $LASTEXITCODE
+ }
+ ExitWithExitCode 0
+}
+catch {
+ Write-Host $_.ScriptStackTrace
+ Write-PipelineTelemetryError -Force -Category 'Sdl' -Message $_
+ ExitWithExitCode 1
+}
diff --git a/eng/common/sdl/packages.config b/eng/common/sdl/packages.config
new file mode 100644
index 000000000..3bd8b29eb
--- /dev/null
+++ b/eng/common/sdl/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/eng/common/sdl/run-sdl.ps1 b/eng/common/sdl/run-sdl.ps1
new file mode 100644
index 000000000..2eac8c78f
--- /dev/null
+++ b/eng/common/sdl/run-sdl.ps1
@@ -0,0 +1,49 @@
+Param(
+ [string] $GuardianCliLocation,
+ [string] $WorkingDirectory,
+ [string] $GdnFolder,
+ [string] $UpdateBaseline,
+ [string] $GuardianLoggerLevel='Standard'
+)
+
+$ErrorActionPreference = 'Stop'
+Set-StrictMode -Version 2.0
+$disableConfigureToolsetImport = $true
+$global:LASTEXITCODE = 0
+
+try {
+ # `tools.ps1` checks $ci to perform some actions. Since the SDL
+ # scripts don't necessarily execute in the same agent that run the
+ # build.ps1/sh script this variable isn't automatically set.
+ $ci = $true
+ . $PSScriptRoot\..\tools.ps1
+
+ # We store config files in the r directory of .gdn
+ $gdnConfigPath = Join-Path $GdnFolder 'r'
+ $ValidPath = Test-Path $GuardianCliLocation
+
+ if ($ValidPath -eq $False)
+ {
+ Write-PipelineTelemetryError -Force -Category 'Sdl' -Message "Invalid Guardian CLI Location."
+ ExitWithExitCode 1
+ }
+
+ $gdnConfigFiles = Get-ChildItem $gdnConfigPath -Recurse -Include '*.gdnconfig'
+ Write-Host "Discovered Guardian config files:"
+ $gdnConfigFiles | Out-String | Write-Host
+
+ Exec-BlockVerbosely {
+ & $GuardianCliLocation run `
+ --working-directory $WorkingDirectory `
+ --baseline mainbaseline `
+ --update-baseline $UpdateBaseline `
+ --logger-level $GuardianLoggerLevel `
+ --config @gdnConfigFiles
+ Exit-IfNZEC "Sdl"
+ }
+}
+catch {
+ Write-Host $_.ScriptStackTrace
+ Write-PipelineTelemetryError -Force -Category 'Sdl' -Message $_
+ ExitWithExitCode 1
+}
diff --git a/eng/common/templates/job/execute-sdl.yml b/eng/common/templates/job/execute-sdl.yml
new file mode 100644
index 000000000..69eb67849
--- /dev/null
+++ b/eng/common/templates/job/execute-sdl.yml
@@ -0,0 +1,185 @@
+parameters:
+ enable: 'false' # Whether the SDL validation job should execute or not
+ overrideParameters: '' # Optional: to override values for parameters.
+ additionalParameters: '' # Optional: parameters that need user specific values eg: '-SourceToolsList @("abc","def") -ArtifactToolsList @("ghi","jkl")'
+ # Optional: if specified, restore and use this version of Guardian instead of the default.
+ overrideGuardianVersion: ''
+ # Optional: if true, publish the '.gdn' folder as a pipeline artifact. This can help with in-depth
+ # diagnosis of problems with specific tool configurations.
+ publishGuardianDirectoryToPipeline: false
+ # The script to run to execute all SDL tools. Use this if you want to use a script to define SDL
+ # parameters rather than relying on YAML. It may be better to use a local script, because you can
+ # reproduce results locally without piecing together a command based on the YAML.
+ executeAllSdlToolsScript: 'eng/common/sdl/execute-all-sdl-tools.ps1'
+ # There is some sort of bug (has been reported) in Azure DevOps where if this parameter is named
+ # 'continueOnError', the parameter value is not correctly picked up.
+ # This can also be remedied by the caller (post-build.yml) if it does not use a nested parameter
+ sdlContinueOnError: false # optional: determines whether to continue the build if the step errors;
+ # optional: determines if build artifacts should be downloaded.
+ downloadArtifacts: true
+ # optional: determines if this job should search the directory of downloaded artifacts for
+ # 'tar.gz' and 'zip' archive files and extract them before running SDL validation tasks.
+ extractArchiveArtifacts: false
+ dependsOn: '' # Optional: dependencies of the job
+ artifactNames: '' # Optional: patterns supplied to DownloadBuildArtifacts
+ # Usage:
+ # artifactNames:
+ # - 'BlobArtifacts'
+ # - 'Artifacts_Windows_NT_Release'
+ # Optional: download a list of pipeline artifacts. 'downloadArtifacts' controls build artifacts,
+ # not pipeline artifacts, so doesn't affect the use of this parameter.
+ pipelineArtifactNames: []
+ # Optional: location and ID of the AzDO build that the build/pipeline artifacts should be
+ # downloaded from. By default, uses runtime expressions to decide based on the variables set by
+ # the 'setupMaestroVars' dependency. Overriding this parameter is necessary if SDL tasks are
+ # running without Maestro++/BAR involved, or to download artifacts from a specific existing build
+ # to iterate quickly on SDL changes.
+ AzDOProjectName: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ]
+ AzDOPipelineId: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ]
+ AzDOBuildId: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ]
+
+jobs:
+- job: Run_SDL
+ dependsOn: ${{ parameters.dependsOn }}
+ displayName: Run SDL tool
+ condition: eq( ${{ parameters.enable }}, 'true')
+ variables:
+ - group: DotNet-VSTS-Bot
+ - name: AzDOProjectName
+ value: ${{ parameters.AzDOProjectName }}
+ - name: AzDOPipelineId
+ value: ${{ parameters.AzDOPipelineId }}
+ - name: AzDOBuildId
+ value: ${{ parameters.AzDOBuildId }}
+ # The Guardian version specified in 'eng/common/sdl/packages.config'. This value must be kept in
+ # sync with the packages.config file.
+ - name: DefaultGuardianVersion
+ value: 0.53.3
+ - name: GuardianVersion
+ value: ${{ coalesce(parameters.overrideGuardianVersion, '$(DefaultGuardianVersion)') }}
+ - name: GuardianPackagesConfigFile
+ value: $(Build.SourcesDirectory)\eng\common\sdl\packages.config
+ pool:
+ # To extract archives (.tar.gz, .zip), we need access to "tar", added in Windows 10/2019.
+ ${{ if eq(parameters.extractArchiveArtifacts, 'false') }}:
+ name: Hosted VS2017
+ ${{ if ne(parameters.extractArchiveArtifacts, 'false') }}:
+ vmImage: windows-2019
+ steps:
+ - checkout: self
+ clean: true
+
+ - ${{ if ne(parameters.downloadArtifacts, 'false')}}:
+ - ${{ if ne(parameters.artifactNames, '') }}:
+ - ${{ each artifactName in parameters.artifactNames }}:
+ - task: DownloadBuildArtifacts@0
+ displayName: Download Build Artifacts
+ inputs:
+ buildType: specific
+ buildVersionToDownload: specific
+ project: $(AzDOProjectName)
+ pipeline: $(AzDOPipelineId)
+ buildId: $(AzDOBuildId)
+ artifactName: ${{ artifactName }}
+ downloadPath: $(Build.ArtifactStagingDirectory)\artifacts
+ checkDownloadedFiles: true
+ - ${{ if eq(parameters.artifactNames, '') }}:
+ - task: DownloadBuildArtifacts@0
+ displayName: Download Build Artifacts
+ inputs:
+ buildType: specific
+ buildVersionToDownload: specific
+ project: $(AzDOProjectName)
+ pipeline: $(AzDOPipelineId)
+ buildId: $(AzDOBuildId)
+ downloadType: specific files
+ itemPattern: "**"
+ downloadPath: $(Build.ArtifactStagingDirectory)\artifacts
+ checkDownloadedFiles: true
+
+ - ${{ each artifactName in parameters.pipelineArtifactNames }}:
+ - task: DownloadPipelineArtifact@2
+ displayName: Download Pipeline Artifacts
+ inputs:
+ buildType: specific
+ buildVersionToDownload: specific
+ project: $(AzDOProjectName)
+ pipeline: $(AzDOPipelineId)
+ buildId: $(AzDOBuildId)
+ artifactName: ${{ artifactName }}
+ downloadPath: $(Build.ArtifactStagingDirectory)\artifacts
+ checkDownloadedFiles: true
+
+ - powershell: eng/common/sdl/extract-artifact-packages.ps1
+ -InputPath $(Build.ArtifactStagingDirectory)\artifacts\BlobArtifacts
+ -ExtractPath $(Build.ArtifactStagingDirectory)\artifacts\BlobArtifacts
+ displayName: Extract Blob Artifacts
+ continueOnError: ${{ parameters.sdlContinueOnError }}
+
+ - powershell: eng/common/sdl/extract-artifact-packages.ps1
+ -InputPath $(Build.ArtifactStagingDirectory)\artifacts\PackageArtifacts
+ -ExtractPath $(Build.ArtifactStagingDirectory)\artifacts\PackageArtifacts
+ displayName: Extract Package Artifacts
+ continueOnError: ${{ parameters.sdlContinueOnError }}
+
+ - ${{ if ne(parameters.extractArchiveArtifacts, 'false') }}:
+ - powershell: eng/common/sdl/extract-artifact-archives.ps1
+ -InputPath $(Build.ArtifactStagingDirectory)\artifacts
+ -ExtractPath $(Build.ArtifactStagingDirectory)\artifacts
+ displayName: Extract Archive Artifacts
+ continueOnError: ${{ parameters.sdlContinueOnError }}
+
+ - ${{ if ne(parameters.overrideGuardianVersion, '') }}:
+ - powershell: |
+ $content = Get-Content $(GuardianPackagesConfigFile)
+
+ Write-Host "packages.config content was:`n$content"
+
+ $content = $content.Replace('$(DefaultGuardianVersion)', '$(GuardianVersion)')
+ $content | Set-Content $(GuardianPackagesConfigFile)
+
+ Write-Host "packages.config content updated to:`n$content"
+ displayName: Use overridden Guardian version ${{ parameters.overrideGuardianVersion }}
+
+ - task: NuGetToolInstaller@1
+ displayName: 'Install NuGet.exe'
+ - task: NuGetCommand@2
+ displayName: 'Install Guardian'
+ inputs:
+ restoreSolution: $(Build.SourcesDirectory)\eng\common\sdl\packages.config
+ feedsToUse: config
+ nugetConfigPath: $(Build.SourcesDirectory)\eng\common\sdl\NuGet.config
+ externalFeedCredentials: GuardianConnect
+ restoreDirectory: $(Build.SourcesDirectory)\.packages
+
+ - ${{ if ne(parameters.overrideParameters, '') }}:
+ - powershell: ${{ parameters.executeAllSdlToolsScript }} ${{ parameters.overrideParameters }}
+ displayName: Execute SDL
+ continueOnError: ${{ parameters.sdlContinueOnError }}
+ - ${{ if eq(parameters.overrideParameters, '') }}:
+ - powershell: ${{ parameters.executeAllSdlToolsScript }}
+ -GuardianPackageName Microsoft.Guardian.Cli.$(GuardianVersion)
+ -NugetPackageDirectory $(Build.SourcesDirectory)\.packages
+ -AzureDevOpsAccessToken $(dn-bot-dotnet-build-rw-code-rw)
+ ${{ parameters.additionalParameters }}
+ displayName: Execute SDL
+ continueOnError: ${{ parameters.sdlContinueOnError }}
+
+ - ${{ if ne(parameters.publishGuardianDirectoryToPipeline, 'false') }}:
+ # We want to publish the Guardian results and configuration for easy diagnosis. However, the
+ # '.gdn' dir is a mix of configuration, results, extracted dependencies, and Guardian default
+ # tooling files. Some of these files are large and aren't useful during an investigation, so
+ # exclude them by simply deleting them before publishing. (As of writing, there is no documented
+ # way to selectively exclude a dir from the pipeline artifact publish task.)
+ - task: DeleteFiles@1
+ displayName: Delete Guardian dependencies to avoid uploading
+ inputs:
+ SourceFolder: $(Agent.BuildDirectory)/.gdn
+ Contents: |
+ c
+ i
+ condition: succeededOrFailed()
+ - publish: $(Agent.BuildDirectory)/.gdn
+ artifact: GuardianConfiguration
+ displayName: Publish GuardianConfiguration
+ condition: succeededOrFailed()
diff --git a/eng/common/templates/job/generate-graph-files.yml b/eng/common/templates/job/generate-graph-files.yml
new file mode 100644
index 000000000..e54ce956f
--- /dev/null
+++ b/eng/common/templates/job/generate-graph-files.yml
@@ -0,0 +1,48 @@
+parameters:
+ # Optional: dependencies of the job
+ dependsOn: ''
+
+ # Optional: A defined YAML pool - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#pool
+ pool: {}
+
+ # Optional: Include toolset dependencies in the generated graph files
+ includeToolset: false
+
+jobs:
+- job: Generate_Graph_Files
+
+ dependsOn: ${{ parameters.dependsOn }}
+
+ displayName: Generate Graph Files
+
+ pool: ${{ parameters.pool }}
+
+ variables:
+ # Publish-Build-Assets provides: MaestroAccessToken, BotAccount-dotnet-maestro-bot-PAT
+ # DotNet-AllOrgs-Darc-Pats provides: dn-bot-devdiv-dnceng-rw-code-pat
+ - group: Publish-Build-Assets
+ - group: DotNet-AllOrgs-Darc-Pats
+ - name: _GraphArguments
+ value: -gitHubPat $(BotAccount-dotnet-maestro-bot-PAT)
+ -azdoPat $(dn-bot-devdiv-dnceng-rw-code-pat)
+ -barToken $(MaestroAccessToken)
+ -outputFolder '$(Build.StagingDirectory)/GraphFiles/'
+ - ${{ if ne(parameters.includeToolset, 'false') }}:
+ - name: _GraphArguments
+ value: ${{ variables._GraphArguments }} -includeToolset
+
+ steps:
+ - task: PowerShell@2
+ displayName: Generate Graph Files
+ inputs:
+ filePath: eng\common\generate-graph-files.ps1
+ arguments: $(_GraphArguments)
+ continueOnError: true
+ - task: PublishBuildArtifacts@1
+ displayName: Publish Graph to Artifacts
+ inputs:
+ PathtoPublish: '$(Build.StagingDirectory)/GraphFiles'
+ PublishLocation: Container
+ ArtifactName: GraphFiles
+ continueOnError: true
+ condition: always()
diff --git a/eng/common/templates/job/job.yml b/eng/common/templates/job/job.yml
new file mode 100644
index 000000000..866967934
--- /dev/null
+++ b/eng/common/templates/job/job.yml
@@ -0,0 +1,244 @@
+# Internal resources (telemetry, microbuild) can only be accessed from non-public projects,
+# and some (Microbuild) should only be applied to non-PR cases for internal builds.
+
+parameters:
+# Job schema parameters - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#job
+ cancelTimeoutInMinutes: ''
+ condition: ''
+ container: ''
+ continueOnError: false
+ dependsOn: ''
+ displayName: ''
+ pool: ''
+ steps: []
+ strategy: ''
+ timeoutInMinutes: ''
+ variables: []
+ workspace: ''
+
+# Job base template specific parameters
+ # See schema documentation - https://github.com/dotnet/arcade/blob/master/Documentation/AzureDevOps/TemplateSchema.md
+ artifacts: ''
+ enableMicrobuild: false
+ enablePublishBuildArtifacts: false
+ enablePublishBuildAssets: false
+ enablePublishTestResults: false
+ enablePublishUsingPipelines: false
+ mergeTestResults: false
+ testRunTitle: ''
+ testResultsFormat: ''
+ name: ''
+ preSteps: []
+ runAsPublic: false
+
+jobs:
+- job: ${{ parameters.name }}
+
+ ${{ if ne(parameters.cancelTimeoutInMinutes, '') }}:
+ cancelTimeoutInMinutes: ${{ parameters.cancelTimeoutInMinutes }}
+
+ ${{ if ne(parameters.condition, '') }}:
+ condition: ${{ parameters.condition }}
+
+ ${{ if ne(parameters.container, '') }}:
+ container: ${{ parameters.container }}
+
+ ${{ if ne(parameters.continueOnError, '') }}:
+ continueOnError: ${{ parameters.continueOnError }}
+
+ ${{ if ne(parameters.dependsOn, '') }}:
+ dependsOn: ${{ parameters.dependsOn }}
+
+ ${{ if ne(parameters.displayName, '') }}:
+ displayName: ${{ parameters.displayName }}
+
+ ${{ if ne(parameters.pool, '') }}:
+ pool: ${{ parameters.pool }}
+
+ ${{ if ne(parameters.strategy, '') }}:
+ strategy: ${{ parameters.strategy }}
+
+ ${{ if ne(parameters.timeoutInMinutes, '') }}:
+ timeoutInMinutes: ${{ parameters.timeoutInMinutes }}
+
+ variables:
+ - ${{ if ne(parameters.enableTelemetry, 'false') }}:
+ - name: DOTNET_CLI_TELEMETRY_PROFILE
+ value: '$(Build.Repository.Uri)'
+ - ${{ if eq(parameters.enableRichCodeNavigation, 'true') }}:
+ - name: EnableRichCodeNavigation
+ value: 'true'
+ - ${{ each variable in parameters.variables }}:
+ # handle name-value variable syntax
+ # example:
+ # - name: [key]
+ # value: [value]
+ - ${{ if ne(variable.name, '') }}:
+ - name: ${{ variable.name }}
+ value: ${{ variable.value }}
+
+ # handle variable groups
+ - ${{ if ne(variable.group, '') }}:
+ - group: ${{ variable.group }}
+
+ # handle key-value variable syntax.
+ # example:
+ # - [key]: [value]
+ - ${{ if and(eq(variable.name, ''), eq(variable.group, '')) }}:
+ - ${{ each pair in variable }}:
+ - name: ${{ pair.key }}
+ value: ${{ pair.value }}
+
+ # DotNet-HelixApi-Access provides 'HelixApiAccessToken' for internal builds
+ - ${{ if and(eq(parameters.enableTelemetry, 'true'), eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+ - group: DotNet-HelixApi-Access
+
+ ${{ if ne(parameters.workspace, '') }}:
+ workspace: ${{ parameters.workspace }}
+
+ steps:
+ - ${{ if ne(parameters.preSteps, '') }}:
+ - ${{ each preStep in parameters.preSteps }}:
+ - ${{ preStep }}
+
+ - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+ - ${{ if eq(parameters.enableMicrobuild, 'true') }}:
+ - task: MicroBuildSigningPlugin@2
+ displayName: Install MicroBuild plugin
+ inputs:
+ signType: $(_SignType)
+ zipSources: false
+ feedSource: https://dnceng.pkgs.visualstudio.com/_packaging/MicroBuildToolset/nuget/v3/index.json
+ env:
+ TeamName: $(_TeamName)
+ continueOnError: ${{ parameters.continueOnError }}
+ condition: and(succeeded(), in(variables['_SignType'], 'real', 'test'), eq(variables['Agent.Os'], 'Windows_NT'))
+
+ - task: NuGetAuthenticate@0
+
+ - ${{ if or(eq(parameters.artifacts.download, 'true'), ne(parameters.artifacts.download, '')) }}:
+ - task: DownloadPipelineArtifact@2
+ inputs:
+ buildType: current
+ artifactName: ${{ coalesce(parameters.artifacts.download.name, 'Artifacts_$(Agent.OS)_$(_BuildConfig)') }}
+ targetPath: ${{ coalesce(parameters.artifacts.download.path, 'artifacts') }}
+ itemPattern: ${{ coalesce(parameters.artifacts.download.pattern, '**') }}
+
+ - ${{ each step in parameters.steps }}:
+ - ${{ step }}
+
+ - ${{ if eq(parameters.enableRichCodeNavigation, true) }}:
+ - task: RichCodeNavIndexer@0
+ displayName: RichCodeNav Upload
+ inputs:
+ languages: ${{ coalesce(parameters.richCodeNavigationLanguage, 'csharp') }}
+ environment: ${{ coalesce(parameters.richCodeNavigationEnvironment, 'production') }}
+ richNavLogOutputDirectory: $(Build.SourcesDirectory)/artifacts/bin
+ continueOnError: true
+
+ - ${{ if eq(parameters.enableMicrobuild, 'true') }}:
+ - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+ - task: MicroBuildCleanup@1
+ displayName: Execute Microbuild cleanup tasks
+ condition: and(always(), in(variables['_SignType'], 'real', 'test'), eq(variables['Agent.Os'], 'Windows_NT'))
+ continueOnError: ${{ parameters.continueOnError }}
+ env:
+ TeamName: $(_TeamName)
+
+ - ${{ if ne(parameters.artifacts.publish, '') }}:
+ - ${{ if or(eq(parameters.artifacts.publish.artifacts, 'true'), ne(parameters.artifacts.publish.artifacts, '')) }}:
+ - task: CopyFiles@2
+ displayName: Gather binaries for publish to artifacts
+ inputs:
+ SourceFolder: 'artifacts/bin'
+ Contents: '**'
+ TargetFolder: '$(Build.ArtifactStagingDirectory)/artifacts/bin'
+ - task: CopyFiles@2
+ displayName: Gather packages for publish to artifacts
+ inputs:
+ SourceFolder: 'artifacts/packages'
+ Contents: '**'
+ TargetFolder: '$(Build.ArtifactStagingDirectory)/artifacts/packages'
+ - task: PublishBuildArtifacts@1
+ displayName: Publish pipeline artifacts
+ inputs:
+ PathtoPublish: '$(Build.ArtifactStagingDirectory)/artifacts'
+ PublishLocation: Container
+ ArtifactName: ${{ coalesce(parameters.artifacts.publish.artifacts.name , 'Artifacts_$(Agent.Os)_$(_BuildConfig)') }}
+ continueOnError: true
+ condition: always()
+ - ${{ if or(eq(parameters.artifacts.publish.logs, 'true'), ne(parameters.artifacts.publish.logs, '')) }}:
+ - publish: artifacts/log
+ artifact: ${{ coalesce(parameters.artifacts.publish.logs.name, 'Logs_Build_$(Agent.Os)_$(_BuildConfig)') }}
+ displayName: Publish logs
+ continueOnError: true
+ condition: always()
+ - ${{ if or(eq(parameters.artifacts.publish.manifests, 'true'), ne(parameters.artifacts.publish.manifests, '')) }}:
+ - ${{ if and(ne(parameters.enablePublishUsingPipelines, 'true'), eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+ - task: CopyFiles@2
+ displayName: Gather Asset Manifests
+ inputs:
+ SourceFolder: '$(Build.SourcesDirectory)/artifacts/log/$(_BuildConfig)/AssetManifest'
+ TargetFolder: '$(Build.ArtifactStagingDirectory)/AssetManifests'
+ continueOnError: ${{ parameters.continueOnError }}
+ condition: and(succeeded(), eq(variables['_DotNetPublishToBlobFeed'], 'true'))
+
+ - task: PublishBuildArtifacts@1
+ displayName: Push Asset Manifests
+ inputs:
+ PathtoPublish: '$(Build.ArtifactStagingDirectory)/AssetManifests'
+ PublishLocation: Container
+ ArtifactName: AssetManifests
+ continueOnError: ${{ parameters.continueOnError }}
+ condition: and(succeeded(), eq(variables['_DotNetPublishToBlobFeed'], 'true'))
+
+ - ${{ if ne(parameters.enablePublishBuildArtifacts, 'false') }}:
+ - task: PublishBuildArtifacts@1
+ displayName: Publish Logs
+ inputs:
+ PathtoPublish: '$(Build.SourcesDirectory)/artifacts/log/$(_BuildConfig)'
+ PublishLocation: Container
+ ArtifactName: ${{ coalesce(parameters.enablePublishBuildArtifacts.artifactName, '$(Agent.Os)_$(Agent.JobName)' ) }}
+ continueOnError: true
+ condition: always()
+
+ - ${{ if or(and(eq(parameters.enablePublishTestResults, 'true'), eq(parameters.testResultsFormat, '')), eq(parameters.testResultsFormat, 'xunit')) }}:
+ - task: PublishTestResults@2
+ displayName: Publish XUnit Test Results
+ inputs:
+ testResultsFormat: 'xUnit'
+ testResultsFiles: '*.xml'
+ searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_BuildConfig)'
+ testRunTitle: ${{ coalesce(parameters.testRunTitle, parameters.name, '$(System.JobName)') }}-xunit
+ mergeTestResults: ${{ parameters.mergeTestResults }}
+ continueOnError: true
+ condition: always()
+ - ${{ if or(and(eq(parameters.enablePublishTestResults, 'true'), eq(parameters.testResultsFormat, '')), eq(parameters.testResultsFormat, 'vstest')) }}:
+ - task: PublishTestResults@2
+ displayName: Publish TRX Test Results
+ inputs:
+ testResultsFormat: 'VSTest'
+ testResultsFiles: '*.trx'
+ searchFolder: '$(Build.SourcesDirectory)/artifacts/TestResults/$(_BuildConfig)'
+ testRunTitle: ${{ coalesce(parameters.testRunTitle, parameters.name, '$(System.JobName)') }}-trx
+ mergeTestResults: ${{ parameters.mergeTestResults }}
+ continueOnError: true
+ condition: always()
+
+ - ${{ if and(eq(parameters.enablePublishBuildAssets, true), ne(parameters.enablePublishUsingPipelines, 'true'), eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+ - task: CopyFiles@2
+ displayName: Gather Asset Manifests
+ inputs:
+ SourceFolder: '$(Build.SourcesDirectory)/artifacts/log/$(_BuildConfig)/AssetManifest'
+ TargetFolder: '$(Build.StagingDirectory)/AssetManifests'
+ continueOnError: ${{ parameters.continueOnError }}
+ condition: and(succeeded(), eq(variables['_DotNetPublishToBlobFeed'], 'true'))
+
+ - task: PublishBuildArtifacts@1
+ displayName: Push Asset Manifests
+ inputs:
+ PathtoPublish: '$(Build.StagingDirectory)/AssetManifests'
+ PublishLocation: Container
+ ArtifactName: AssetManifests
+ continueOnError: ${{ parameters.continueOnError }}
+ condition: and(succeeded(), eq(variables['_DotNetPublishToBlobFeed'], 'true'))
diff --git a/eng/common/templates/job/onelocbuild.yml b/eng/common/templates/job/onelocbuild.yml
new file mode 100644
index 000000000..e8bc77d2e
--- /dev/null
+++ b/eng/common/templates/job/onelocbuild.yml
@@ -0,0 +1,93 @@
+parameters:
+ # Optional: dependencies of the job
+ dependsOn: ''
+
+ # Optional: A defined YAML pool - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#pool
+ pool:
+ vmImage: vs2017-win2016
+
+ CeapexPat: $(dn-bot-ceapex-package-r) # PAT for the loc AzDO instance https://dev.azure.com/ceapex
+ GithubPat: $(BotAccount-dotnet-bot-repo-PAT)
+
+ SourcesDirectory: $(Build.SourcesDirectory)
+ CreatePr: true
+ AutoCompletePr: false
+ UseLfLineEndings: true
+ UseCheckedInLocProjectJson: false
+ LanguageSet: VS_Main_Languages
+ LclSource: lclFilesInRepo
+ LclPackageId: ''
+ RepoType: gitHub
+ GitHubOrg: dotnet
+ MirrorRepo: ''
+ MirrorBranch: main
+ condition: ''
+
+jobs:
+- job: OneLocBuild
+
+ dependsOn: ${{ parameters.dependsOn }}
+
+ displayName: OneLocBuild
+
+ pool: ${{ parameters.pool }}
+
+ variables:
+ - group: OneLocBuildVariables # Contains the CeapexPat and GithubPat
+ - name: _GenerateLocProjectArguments
+ value: -SourcesDirectory ${{ parameters.SourcesDirectory }}
+ -LanguageSet "${{ parameters.LanguageSet }}"
+ -CreateNeutralXlfs
+ - ${{ if eq(parameters.UseCheckedInLocProjectJson, 'true') }}:
+ - name: _GenerateLocProjectArguments
+ value: ${{ variables._GenerateLocProjectArguments }} -UseCheckedInLocProjectJson
+
+
+ steps:
+ - task: Powershell@2
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/generate-locproject.ps1
+ arguments: $(_GenerateLocProjectArguments)
+ displayName: Generate LocProject.json
+ condition: ${{ parameters.condition }}
+
+ - task: OneLocBuild@2
+ displayName: OneLocBuild
+ env:
+ SYSTEM_ACCESSTOKEN: $(System.AccessToken)
+ inputs:
+ locProj: eng/Localize/LocProject.json
+ outDir: $(Build.ArtifactStagingDirectory)
+ lclSource: ${{ parameters.LclSource }}
+ lclPackageId: ${{ parameters.LclPackageId }}
+ isCreatePrSelected: ${{ parameters.CreatePr }}
+ ${{ if eq(parameters.CreatePr, true) }}:
+ isAutoCompletePrSelected: ${{ parameters.AutoCompletePr }}
+ isUseLfLineEndingsSelected: ${{ parameters.UseLfLineEndings }}
+ packageSourceAuth: patAuth
+ patVariable: ${{ parameters.CeapexPat }}
+ ${{ if eq(parameters.RepoType, 'gitHub') }}:
+ repoType: ${{ parameters.RepoType }}
+ gitHubPatVariable: "${{ parameters.GithubPat }}"
+ ${{ if ne(parameters.MirrorRepo, '') }}:
+ isMirrorRepoSelected: true
+ gitHubOrganization: ${{ parameters.GitHubOrg }}
+ mirrorRepo: ${{ parameters.MirrorRepo }}
+ mirrorBranch: ${{ parameters.MirrorBranch }}
+ condition: ${{ parameters.condition }}
+
+ - task: PublishBuildArtifacts@1
+ displayName: Publish Localization Files
+ inputs:
+ PathtoPublish: '$(Build.ArtifactStagingDirectory)/loc'
+ PublishLocation: Container
+ ArtifactName: Loc
+ condition: ${{ parameters.condition }}
+
+ - task: PublishBuildArtifacts@1
+ displayName: Publish LocProject.json
+ inputs:
+ PathtoPublish: '$(Build.SourcesDirectory)/eng/Localize/'
+ PublishLocation: Container
+ ArtifactName: Loc
+ condition: ${{ parameters.condition }}
\ No newline at end of file
diff --git a/eng/common/templates/job/publish-build-assets.yml b/eng/common/templates/job/publish-build-assets.yml
new file mode 100644
index 000000000..3b9e2524f
--- /dev/null
+++ b/eng/common/templates/job/publish-build-assets.yml
@@ -0,0 +1,101 @@
+parameters:
+ configuration: 'Debug'
+
+ # Optional: condition for the job to run
+ condition: ''
+
+ # Optional: 'true' if future jobs should run even if this job fails
+ continueOnError: false
+
+ # Optional: dependencies of the job
+ dependsOn: ''
+
+ # Optional: Include PublishBuildArtifacts task
+ enablePublishBuildArtifacts: false
+
+ # Optional: A defined YAML pool - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#pool
+ pool: {}
+
+ # Optional: should run as a public build even in the internal project
+ # if 'true', the build won't run any of the internal only steps, even if it is running in non-public projects.
+ runAsPublic: false
+
+ # Optional: whether the build's artifacts will be published using release pipelines or direct feed publishing
+ publishUsingPipelines: false
+
+jobs:
+- job: Asset_Registry_Publish
+
+ dependsOn: ${{ parameters.dependsOn }}
+
+ displayName: Publish to Build Asset Registry
+
+ pool: ${{ parameters.pool }}
+
+ variables:
+ - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+ - name: _BuildConfig
+ value: ${{ parameters.configuration }}
+ - group: Publish-Build-Assets
+ - group: AzureDevOps-Artifact-Feeds-Pats
+ # Skip component governance and codesign validation for SDL. These jobs
+ # create no content.
+ - name: skipComponentGovernanceDetection
+ value: true
+ - name: runCodesignValidationInjection
+ value: false
+
+ steps:
+ - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+ - task: DownloadBuildArtifacts@0
+ displayName: Download artifact
+ inputs:
+ artifactName: AssetManifests
+ downloadPath: '$(Build.StagingDirectory)/Download'
+ checkDownloadedFiles: true
+ condition: ${{ parameters.condition }}
+ continueOnError: ${{ parameters.continueOnError }}
+
+ - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+ - task: NuGetAuthenticate@0
+
+ - task: PowerShell@2
+ displayName: Enable cross-org NuGet feed authentication
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/enable-cross-org-publishing.ps1
+ arguments: -token $(dn-bot-all-orgs-artifact-feeds-rw)
+
+ - task: PowerShell@2
+ displayName: Publish Build Assets
+ inputs:
+ filePath: eng\common\sdk-task.ps1
+ arguments: -task PublishBuildAssets -restore -msbuildEngine dotnet
+ /p:ManifestsPath='$(Build.StagingDirectory)/Download/AssetManifests'
+ /p:BuildAssetRegistryToken=$(MaestroAccessToken)
+ /p:MaestroApiEndpoint=https://maestro-prod.westus2.cloudapp.azure.com
+ /p:PublishUsingPipelines=${{ parameters.publishUsingPipelines }}
+ /p:Configuration=$(_BuildConfig)
+ /p:OfficialBuildId=$(Build.BuildNumber)
+ condition: ${{ parameters.condition }}
+ continueOnError: ${{ parameters.continueOnError }}
+
+ - task: powershell@2
+ displayName: Create ReleaseConfigs Artifact
+ inputs:
+ targetType: inline
+ script: |
+ Add-Content -Path "$(Build.StagingDirectory)/ReleaseConfigs.txt" -Value $(BARBuildId)
+ Add-Content -Path "$(Build.StagingDirectory)/ReleaseConfigs.txt" -Value "$(DefaultChannels)"
+ Add-Content -Path "$(Build.StagingDirectory)/ReleaseConfigs.txt" -Value $(IsStableBuild)
+
+ - task: PublishBuildArtifacts@1
+ displayName: Publish ReleaseConfigs Artifact
+ inputs:
+ PathtoPublish: '$(Build.StagingDirectory)/ReleaseConfigs.txt'
+ PublishLocation: Container
+ ArtifactName: ReleaseConfigs
+
+ - ${{ if eq(parameters.enablePublishBuildArtifacts, 'true') }}:
+ - template: /eng/common/templates/steps/publish-logs.yml
+ parameters:
+ JobLabel: 'Publish_Artifacts_Logs'
diff --git a/eng/common/templates/job/source-build.yml b/eng/common/templates/job/source-build.yml
new file mode 100644
index 000000000..5023d36dc
--- /dev/null
+++ b/eng/common/templates/job/source-build.yml
@@ -0,0 +1,60 @@
+parameters:
+ # This template adds arcade-powered source-build to CI. The template produces a server job with a
+ # default ID 'Source_Build_Complete' to put in a dependency list if necessary.
+
+ # Specifies the prefix for source-build jobs added to pipeline. Use this if disambiguation needed.
+ jobNamePrefix: 'Source_Build'
+
+ # Defines the platform on which to run the job. By default, a linux-x64 machine, suitable for
+ # managed-only repositories. This is an object with these properties:
+ #
+ # name: ''
+ # The name of the job. This is included in the job ID.
+ # targetRID: ''
+ # The name of the target RID to use, instead of the one auto-detected by Arcade.
+ # nonPortable: false
+ # Enables non-portable mode. This means a more specific RID (e.g. fedora.32-x64 rather than
+ # linux-x64), and compiling against distro-provided packages rather than portable ones.
+ # skipPublishValidation: false
+ # Disables publishing validation. By default, a check is performed to ensure no packages are
+ # published by source-build.
+ # container: ''
+ # A container to use. Runs in docker.
+ # pool: {}
+ # A pool to use. Runs directly on an agent.
+ # buildScript: ''
+ # Specifies the build script to invoke to perform the build in the repo. The default
+ # './build.sh' should work for typical Arcade repositories, but this is customizable for
+ # difficult situations.
+ # jobProperties: {}
+ # A list of job properties to inject at the top level, for potential extensibility beyond
+ # container and pool.
+ platform: {}
+
+ # The default VM host AzDO pool. This should be capable of running Docker containers: almost all
+ # source-build builds run in Docker, including the default managed platform.
+ defaultContainerHostPool:
+ vmImage: ubuntu-20.04
+
+jobs:
+- job: ${{ parameters.jobNamePrefix }}_${{ parameters.platform.name }}
+ displayName: Source-Build (${{ parameters.platform.name }})
+
+ ${{ each property in parameters.platform.jobProperties }}:
+ ${{ property.key }}: ${{ property.value }}
+
+ ${{ if ne(parameters.platform.container, '') }}:
+ container: ${{ parameters.platform.container }}
+
+ ${{ if eq(parameters.platform.pool, '') }}:
+ pool: ${{ parameters.defaultContainerHostPool }}
+ ${{ if ne(parameters.platform.pool, '') }}:
+ pool: ${{ parameters.platform.pool }}
+
+ workspace:
+ clean: all
+
+ steps:
+ - template: /eng/common/templates/steps/source-build.yml
+ parameters:
+ platform: ${{ parameters.platform }}
diff --git a/eng/common/templates/job/source-index-stage1.yml b/eng/common/templates/job/source-index-stage1.yml
new file mode 100644
index 000000000..b58d42364
--- /dev/null
+++ b/eng/common/templates/job/source-index-stage1.yml
@@ -0,0 +1,62 @@
+parameters:
+ runAsPublic: false
+ sourceIndexPackageVersion: 1.0.1-20210614.1
+ sourceIndexPackageSource: https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json
+ sourceIndexBuildCommand: powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -Command "eng/common/build.ps1 -restore -build -binarylog -ci"
+ preSteps: []
+ binlogPath: artifacts/log/Debug/Build.binlog
+ pool:
+ vmImage: vs2017-win2016
+ condition: ''
+ dependsOn: ''
+
+jobs:
+- job: SourceIndexStage1
+ dependsOn: ${{ parameters.dependsOn }}
+ condition: ${{ parameters.condition }}
+ variables:
+ - name: SourceIndexPackageVersion
+ value: ${{ parameters.sourceIndexPackageVersion }}
+ - name: SourceIndexPackageSource
+ value: ${{ parameters.sourceIndexPackageSource }}
+ - name: BinlogPath
+ value: ${{ parameters.binlogPath }}
+ - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+ - group: source-dot-net stage1 variables
+
+ pool: ${{ parameters.pool }}
+ steps:
+ - ${{ each preStep in parameters.preSteps }}:
+ - ${{ preStep }}
+
+ - task: UseDotNet@2
+ displayName: Use .NET Core sdk 3.1
+ inputs:
+ packageType: sdk
+ version: 3.1.x
+
+ - task: UseDotNet@2
+ displayName: Use .NET Core sdk
+ inputs:
+ useGlobalJson: true
+
+ - script: |
+ dotnet tool install BinLogToSln --version $(SourceIndexPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path .source-index/tools
+ dotnet tool install UploadIndexStage1 --version $(SourceIndexPackageVersion) --add-source $(SourceIndexPackageSource) --tool-path .source-index/tools
+ echo ##vso[task.prependpath]$(Build.SourcesDirectory)/.source-index/tools
+ displayName: Download Tools
+
+ - script: ${{ parameters.sourceIndexBuildCommand }}
+ displayName: Build Repository
+
+ - script: BinLogToSln -i $(BinlogPath) -r $(Build.SourcesDirectory) -n $(Build.Repository.Name) -o .source-index/stage1output
+ displayName: Process Binlog into indexable sln
+ env:
+ DOTNET_ROLL_FORWARD_ON_NO_CANDIDATE_FX: 2
+
+ - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+ - script: UploadIndexStage1 -i .source-index/stage1output -n $(Build.Repository.Name)
+ displayName: Upload stage1 artifacts to source index
+ env:
+ BLOB_CONTAINER_URL: $(source-dot-net-stage1-blob-container-url)
+ DOTNET_ROLL_FORWARD_ON_NO_CANDIDATE_FX: 2
diff --git a/eng/common/templates/jobs/jobs.yml b/eng/common/templates/jobs/jobs.yml
new file mode 100644
index 000000000..a1f8fce96
--- /dev/null
+++ b/eng/common/templates/jobs/jobs.yml
@@ -0,0 +1,99 @@
+parameters:
+ # See schema documentation in /Documentation/AzureDevOps/TemplateSchema.md
+ continueOnError: false
+
+ # Optional: Include PublishBuildArtifacts task
+ enablePublishBuildArtifacts: false
+
+ # Optional: Enable publishing using release pipelines
+ enablePublishUsingPipelines: false
+
+ # Optional: Enable running the source-build jobs to build repo from source
+ enableSourceBuild: false
+
+ # Optional: Parameters for source-build template.
+ # See /eng/common/templates/jobs/source-build.yml for options
+ sourceBuildParameters: []
+
+ graphFileGeneration:
+ # Optional: Enable generating the graph files at the end of the build
+ enabled: false
+ # Optional: Include toolset dependencies in the generated graph files
+ includeToolset: false
+
+ # Required: A collection of jobs to run - https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema?view=vsts&tabs=schema#job
+ jobs: []
+
+ # Optional: Override automatically derived dependsOn value for "publish build assets" job
+ publishBuildAssetsDependsOn: ''
+
+ # Optional: should run as a public build even in the internal project
+ # if 'true', the build won't run any of the internal only steps, even if it is running in non-public projects.
+ runAsPublic: false
+
+ enableSourceIndex: false
+ sourceIndexParams: {}
+
+# Internal resources (telemetry, microbuild) can only be accessed from non-public projects,
+# and some (Microbuild) should only be applied to non-PR cases for internal builds.
+
+jobs:
+- ${{ each job in parameters.jobs }}:
+ - template: ../job/job.yml
+ parameters:
+ # pass along parameters
+ ${{ each parameter in parameters }}:
+ ${{ if ne(parameter.key, 'jobs') }}:
+ ${{ parameter.key }}: ${{ parameter.value }}
+
+ # pass along job properties
+ ${{ each property in job }}:
+ ${{ if ne(property.key, 'job') }}:
+ ${{ property.key }}: ${{ property.value }}
+
+ name: ${{ job.job }}
+
+- ${{ if eq(parameters.enableSourceBuild, true) }}:
+ - template: /eng/common/templates/jobs/source-build.yml
+ parameters:
+ allCompletedJobId: Source_Build_Complete
+ ${{ each parameter in parameters.sourceBuildParameters }}:
+ ${{ parameter.key }}: ${{ parameter.value }}
+
+- ${{ if eq(parameters.enableSourceIndex, 'true') }}:
+ - template: ../job/source-index-stage1.yml
+ parameters:
+ runAsPublic: ${{ parameters.runAsPublic }}
+ ${{ each parameter in parameters.sourceIndexParams }}:
+ ${{ parameter.key }}: ${{ parameter.value }}
+
+- ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+
+ - ${{ if or(eq(parameters.enablePublishBuildAssets, true), eq(parameters.artifacts.publish.manifests, 'true'), ne(parameters.artifacts.publish.manifests, '')) }}:
+ - template: ../job/publish-build-assets.yml
+ parameters:
+ continueOnError: ${{ parameters.continueOnError }}
+ dependsOn:
+ - ${{ if ne(parameters.publishBuildAssetsDependsOn, '') }}:
+ - ${{ each job in parameters.publishBuildAssetsDependsOn }}:
+ - ${{ job.job }}
+ - ${{ if eq(parameters.publishBuildAssetsDependsOn, '') }}:
+ - ${{ each job in parameters.jobs }}:
+ - ${{ job.job }}
+ - ${{ if eq(parameters.enableSourceBuild, true) }}:
+ - Source_Build_Complete
+ pool:
+ vmImage: vs2017-win2016
+ runAsPublic: ${{ parameters.runAsPublic }}
+ publishUsingPipelines: ${{ parameters.enablePublishUsingPipelines }}
+ enablePublishBuildArtifacts: ${{ parameters.enablePublishBuildArtifacts }}
+
+ - ${{ if eq(parameters.graphFileGeneration.enabled, true) }}:
+ - template: ../job/generate-graph-files.yml
+ parameters:
+ continueOnError: ${{ parameters.continueOnError }}
+ includeToolset: ${{ parameters.graphFileGeneration.includeToolset }}
+ dependsOn:
+ - Asset_Registry_Publish
+ pool:
+ vmImage: vs2017-win2016
diff --git a/eng/common/templates/jobs/source-build.yml b/eng/common/templates/jobs/source-build.yml
new file mode 100644
index 000000000..00aa98eb3
--- /dev/null
+++ b/eng/common/templates/jobs/source-build.yml
@@ -0,0 +1,46 @@
+parameters:
+ # This template adds arcade-powered source-build to CI. A job is created for each platform, as
+ # well as an optional server job that completes when all platform jobs complete.
+
+ # The name of the "join" job for all source-build platforms. If set to empty string, the job is
+ # not included. Existing repo pipelines can use this job depend on all source-build jobs
+ # completing without maintaining a separate list of every single job ID: just depend on this one
+ # server job. By default, not included. Recommended name if used: 'Source_Build_Complete'.
+ allCompletedJobId: ''
+
+ # See /eng/common/templates/job/source-build.yml
+ jobNamePrefix: 'Source_Build'
+
+ # This is the default platform provided by Arcade, intended for use by a managed-only repo.
+ defaultManagedPlatform:
+ name: 'Managed'
+ container: 'mcr.microsoft.com/dotnet-buildtools/prereqs:centos-7-3e800f1-20190501005343'
+
+ # Defines the platforms on which to run build jobs. One job is created for each platform, and the
+ # object in this array is sent to the job template as 'platform'. If no platforms are specified,
+ # one job runs on 'defaultManagedPlatform'.
+ platforms: []
+
+jobs:
+
+- ${{ if ne(parameters.allCompletedJobId, '') }}:
+ - job: ${{ parameters.allCompletedJobId }}
+ displayName: Source-Build Complete
+ pool: server
+ dependsOn:
+ - ${{ each platform in parameters.platforms }}:
+ - ${{ parameters.jobNamePrefix }}_${{ platform.name }}
+ - ${{ if eq(length(parameters.platforms), 0) }}:
+ - ${{ parameters.jobNamePrefix }}_${{ parameters.defaultManagedPlatform.name }}
+
+- ${{ each platform in parameters.platforms }}:
+ - template: /eng/common/templates/job/source-build.yml
+ parameters:
+ jobNamePrefix: ${{ parameters.jobNamePrefix }}
+ platform: ${{ platform }}
+
+- ${{ if eq(length(parameters.platforms), 0) }}:
+ - template: /eng/common/templates/job/source-build.yml
+ parameters:
+ jobNamePrefix: ${{ parameters.jobNamePrefix }}
+ platform: ${{ parameters.defaultManagedPlatform }}
diff --git a/eng/common/templates/phases/base.yml b/eng/common/templates/phases/base.yml
new file mode 100644
index 000000000..0123cf43b
--- /dev/null
+++ b/eng/common/templates/phases/base.yml
@@ -0,0 +1,130 @@
+parameters:
+ # Optional: Clean sources before building
+ clean: true
+
+ # Optional: Git fetch depth
+ fetchDepth: ''
+
+ # Optional: name of the phase (not specifying phase name may cause name collisions)
+ name: ''
+ # Optional: display name of the phase
+ displayName: ''
+
+ # Optional: condition for the job to run
+ condition: ''
+
+ # Optional: dependencies of the phase
+ dependsOn: ''
+
+ # Required: A defined YAML queue
+ queue: {}
+
+ # Required: build steps
+ steps: []
+
+ # Optional: variables
+ variables: {}
+
+ # Optional: should run as a public build even in the internal project
+ # if 'true', the build won't run any of the internal only steps, even if it is running in non-public projects.
+ runAsPublic: false
+
+ ## Telemetry variables
+
+ # Optional: enable sending telemetry
+ # if 'true', these "variables" must be specified in the variables object or as part of the queue matrix
+ # _HelixBuildConfig - differentiate between Debug, Release, other
+ # _HelixSource - Example: build/product
+ # _HelixType - Example: official/dotnet/arcade/$(Build.SourceBranch)
+ enableTelemetry: false
+
+ # Optional: Enable installing Microbuild plugin
+ # if 'true', these "variables" must be specified in the variables object or as part of the queue matrix
+ # _TeamName - the name of your team
+ # _SignType - 'test' or 'real'
+ enableMicrobuild: false
+
+# Internal resources (telemetry, microbuild) can only be accessed from non-public projects,
+# and some (Microbuild) should only be applied to non-PR cases for internal builds.
+
+phases:
+- phase: ${{ parameters.name }}
+
+ ${{ if ne(parameters.displayName, '') }}:
+ displayName: ${{ parameters.displayName }}
+
+ ${{ if ne(parameters.condition, '') }}:
+ condition: ${{ parameters.condition }}
+
+ ${{ if ne(parameters.dependsOn, '') }}:
+ dependsOn: ${{ parameters.dependsOn }}
+
+ queue: ${{ parameters.queue }}
+
+ ${{ if ne(parameters.variables, '') }}:
+ variables:
+ ${{ insert }}: ${{ parameters.variables }}
+
+ steps:
+ - checkout: self
+ clean: ${{ parameters.clean }}
+ ${{ if ne(parameters.fetchDepth, '') }}:
+ fetchDepth: ${{ parameters.fetchDepth }}
+
+ - ${{ if eq(parameters.enableTelemetry, 'true') }}:
+ - template: /eng/common/templates/steps/telemetry-start.yml
+ parameters:
+ buildConfig: $(_HelixBuildConfig)
+ helixSource: $(_HelixSource)
+ helixType: $(_HelixType)
+ runAsPublic: ${{ parameters.runAsPublic }}
+
+ - ${{ if eq(parameters.enableMicrobuild, 'true') }}:
+ # Internal only resource, and Microbuild signing shouldn't be applied to PRs.
+ - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+ - task: MicroBuildSigningPlugin@2
+ displayName: Install MicroBuild plugin
+ inputs:
+ signType: $(_SignType)
+ zipSources: false
+ feedSource: https://dnceng.pkgs.visualstudio.com/_packaging/MicroBuildToolset/nuget/v3/index.json
+
+ env:
+ TeamName: $(_TeamName)
+ continueOnError: false
+ condition: and(succeeded(), in(variables['_SignType'], 'real', 'test'), eq(variables['Agent.Os'], 'Windows_NT'))
+
+ # Run provided build steps
+ - ${{ parameters.steps }}
+
+ - ${{ if eq(parameters.enableMicrobuild, 'true') }}:
+ # Internal only resources
+ - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+ - task: MicroBuildCleanup@1
+ displayName: Execute Microbuild cleanup tasks
+ condition: and(always(), in(variables['_SignType'], 'real', 'test'), eq(variables['Agent.Os'], 'Windows_NT'))
+ env:
+ TeamName: $(_TeamName)
+
+ - ${{ if eq(parameters.enableTelemetry, 'true') }}:
+ - template: /eng/common/templates/steps/telemetry-end.yml
+ parameters:
+ helixSource: $(_HelixSource)
+ helixType: $(_HelixType)
+
+ - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+ - task: CopyFiles@2
+ displayName: Gather Asset Manifests
+ inputs:
+ SourceFolder: '$(Build.SourcesDirectory)/artifacts/log/$(_BuildConfig)/AssetManifest'
+ TargetFolder: '$(Build.StagingDirectory)/AssetManifests'
+ continueOnError: false
+ condition: and(succeeded(), eq(variables['_DotNetPublishToBlobFeed'], 'true'))
+ - task: PublishBuildArtifacts@1
+ displayName: Push Asset Manifests
+ inputs:
+ PathtoPublish: '$(Build.StagingDirectory)/AssetManifests'
+ PublishLocation: Container
+ ArtifactName: AssetManifests
+ continueOnError: false
+ condition: and(succeeded(), eq(variables['_DotNetPublishToBlobFeed'], 'true'))
diff --git a/eng/common/templates/phases/publish-build-assets.yml b/eng/common/templates/phases/publish-build-assets.yml
new file mode 100644
index 000000000..4e51e472e
--- /dev/null
+++ b/eng/common/templates/phases/publish-build-assets.yml
@@ -0,0 +1,52 @@
+parameters:
+ dependsOn: ''
+ queue: {}
+ configuration: 'Debug'
+ condition: succeeded()
+ continueOnError: false
+ runAsPublic: false
+ publishUsingPipelines: false
+phases:
+ - phase: Asset_Registry_Publish
+ displayName: Publish to Build Asset Registry
+ dependsOn: ${{ parameters.dependsOn }}
+ queue: ${{ parameters.queue }}
+ variables:
+ _BuildConfig: ${{ parameters.configuration }}
+ steps:
+ - ${{ if and(eq(parameters.runAsPublic, 'false'), ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}:
+ - task: DownloadBuildArtifacts@0
+ displayName: Download artifact
+ inputs:
+ artifactName: AssetManifests
+ downloadPath: '$(Build.StagingDirectory)/Download'
+ checkDownloadedFiles: true
+ condition: ${{ parameters.condition }}
+ continueOnError: ${{ parameters.continueOnError }}
+ - task: AzureKeyVault@1
+ inputs:
+ azureSubscription: 'DotNet-Engineering-Services_KeyVault'
+ KeyVaultName: EngKeyVault
+ SecretsFilter: 'MaestroAccessToken'
+ condition: ${{ parameters.condition }}
+ continueOnError: ${{ parameters.continueOnError }}
+ - task: PowerShell@2
+ displayName: Publish Build Assets
+ inputs:
+ filePath: eng\common\sdk-task.ps1
+ arguments: -task PublishBuildAssets -restore -msbuildEngine dotnet
+ /p:ManifestsPath='$(Build.StagingDirectory)/Download/AssetManifests'
+ /p:BuildAssetRegistryToken=$(MaestroAccessToken)
+ /p:MaestroApiEndpoint=https://maestro-prod.westus2.cloudapp.azure.com
+ /p:PublishUsingPipelines=${{ parameters.publishUsingPipelines }}
+ /p:Configuration=$(_BuildConfig)
+ condition: ${{ parameters.condition }}
+ continueOnError: ${{ parameters.continueOnError }}
+ - task: PublishBuildArtifacts@1
+ displayName: Publish Logs to VSTS
+ inputs:
+ PathtoPublish: '$(Build.SourcesDirectory)/artifacts/log/$(_BuildConfig)'
+ PublishLocation: Container
+ ArtifactName: $(Agent.Os)_Asset_Registry_Publish
+ continueOnError: true
+ condition: always()
diff --git a/eng/common/templates/post-build/channels/generic-internal-channel.yml b/eng/common/templates/post-build/channels/generic-internal-channel.yml
new file mode 100644
index 000000000..8990dfc8c
--- /dev/null
+++ b/eng/common/templates/post-build/channels/generic-internal-channel.yml
@@ -0,0 +1,190 @@
+parameters:
+ BARBuildId: ''
+ PromoteToChannelIds: ''
+ artifactsPublishingAdditionalParameters: ''
+ dependsOn:
+ - Validate
+ publishInstallersAndChecksums: true
+ symbolPublishingAdditionalParameters: ''
+ stageName: ''
+ channelName: ''
+ channelId: ''
+ transportFeed: ''
+ shippingFeed: ''
+ symbolsFeed: ''
+
+stages:
+- stage: ${{ parameters.stageName }}
+ dependsOn: ${{ parameters.dependsOn }}
+ variables:
+ - template: ../common-variables.yml
+ displayName: ${{ parameters.channelName }} Publishing
+ jobs:
+ - template: ../setup-maestro-vars.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+
+ - job: publish_symbols
+ displayName: Symbol Publishing
+ dependsOn: setupMaestroVars
+ condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.TargetChannels'], format('[{0}]', ${{ parameters.channelId }} ))
+ variables:
+ - group: DotNet-Symbol-Server-Pats
+ - name: AzDOProjectName
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ]
+ - name: AzDOPipelineId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ]
+ - name: AzDOBuildId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ]
+ pool:
+ vmImage: 'windows-2019'
+ steps:
+ - script: echo "##vso[task.logissue type=warning]Going forward, v2 Arcade publishing is no longer supported. Please read https://github.com/dotnet/arcade/blob/main/Documentation/CorePackages/Publishing.md for details, then contact dnceng if you have further questions."
+ displayName: Warn about v2 Arcade Publishing Usage
+
+ # This is necessary whenever we want to publish/restore to an AzDO private feed
+ - task: NuGetAuthenticate@0
+ displayName: 'Authenticate to AzDO Feeds'
+
+ - task: DownloadBuildArtifacts@0
+ displayName: Download Build Assets
+ continueOnError: true
+ inputs:
+ buildType: specific
+ buildVersionToDownload: specific
+ project: $(AzDOProjectName)
+ pipeline: $(AzDOPipelineId)
+ buildId: $(AzDOBuildId)
+ downloadType: 'specific'
+ itemPattern: |
+ PdbArtifacts/**
+ BlobArtifacts/**
+ downloadPath: '$(Build.ArtifactStagingDirectory)'
+ checkDownloadedFiles: true
+
+ # This is necessary whenever we want to publish/restore to an AzDO private feed
+ # Since sdk-task.ps1 tries to restore packages we need to do this authentication here
+ # otherwise it'll complain about accessing a private feed.
+ - task: NuGetAuthenticate@0
+ displayName: 'Authenticate to AzDO Feeds'
+
+ - task: PowerShell@2
+ displayName: Enable cross-org publishing
+ inputs:
+ filePath: eng\common\enable-cross-org-publishing.ps1
+ arguments: -token $(dn-bot-dnceng-artifact-feeds-rw)
+
+ - task: PowerShell@2
+ displayName: Publish
+ inputs:
+ filePath: eng\common\sdk-task.ps1
+ arguments: -task PublishToSymbolServers -restore -msbuildEngine dotnet
+ /p:DotNetSymbolServerTokenMsdl=$(microsoft-symbol-server-pat)
+ /p:DotNetSymbolServerTokenSymWeb=$(symweb-symbol-server-pat)
+ /p:PDBArtifactsDirectory='$(Build.ArtifactStagingDirectory)/PDBArtifacts/'
+ /p:BlobBasePath='$(Build.ArtifactStagingDirectory)/BlobArtifacts/'
+ /p:SymbolPublishingExclusionsFile='$(Build.SourcesDirectory)/eng/SymbolPublishingExclusionsFile.txt'
+ /p:Configuration=Release
+ /p:PublishToMSDL=false
+ ${{ parameters.symbolPublishingAdditionalParameters }}
+
+ - template: ../../steps/publish-logs.yml
+ parameters:
+ StageLabel: '${{ parameters.stageName }}'
+ JobLabel: 'SymbolPublishing'
+
+ - job: publish_assets
+ displayName: Publish Assets
+ dependsOn: setupMaestroVars
+ timeoutInMinutes: 120
+ variables:
+ - name: BARBuildId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ]
+ - name: IsStableBuild
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.IsStableBuild'] ]
+ - name: AzDOProjectName
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ]
+ - name: AzDOPipelineId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ]
+ - name: AzDOBuildId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ]
+ condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.TargetChannels'], format('[{0}]', ${{ parameters.channelId }} ))
+ pool:
+ vmImage: 'windows-2019'
+ steps:
+ - script: echo "##vso[task.logissue type=warning]Going forward, v2 Arcade publishing is no longer supported. Please read https://github.com/dotnet/arcade/blob/main/Documentation/CorePackages/Publishing.md for details, then contact dnceng if you have further questions."
+ displayName: Warn about v2 Arcade Publishing Usage
+
+ - task: DownloadBuildArtifacts@0
+ displayName: Download Build Assets
+ continueOnError: true
+ inputs:
+ buildType: specific
+ buildVersionToDownload: specific
+ project: $(AzDOProjectName)
+ pipeline: $(AzDOPipelineId)
+ buildId: $(AzDOBuildId)
+ downloadType: 'specific'
+ itemPattern: |
+ PackageArtifacts/**
+ BlobArtifacts/**
+ AssetManifests/**
+ downloadPath: '$(Build.ArtifactStagingDirectory)'
+ checkDownloadedFiles: true
+
+ - task: NuGetToolInstaller@1
+ displayName: 'Install NuGet.exe'
+
+ # This is necessary whenever we want to publish/restore to an AzDO private feed
+ - task: NuGetAuthenticate@0
+ displayName: 'Authenticate to AzDO Feeds'
+
+ - task: PowerShell@2
+ displayName: Enable cross-org publishing
+ inputs:
+ filePath: eng\common\enable-cross-org-publishing.ps1
+ arguments: -token $(dn-bot-dnceng-artifact-feeds-rw)
+
+ - task: PowerShell@2
+ displayName: Publish Assets
+ inputs:
+ filePath: eng\common\sdk-task.ps1
+ arguments: -task PublishArtifactsInManifest -restore -msbuildEngine dotnet
+ /p:PublishingInfraVersion=2
+ /p:IsStableBuild=$(IsStableBuild)
+ /p:IsInternalBuild=$(IsInternalBuild)
+ /p:RepositoryName=$(Build.Repository.Name)
+ /p:CommitSha=$(Build.SourceVersion)
+ /p:NugetPath=$(NuGetExeToolPath)
+ /p:AzdoTargetFeedPAT='$(dn-bot-dnceng-universal-packages-rw)'
+ /p:AzureStorageTargetFeedPAT='$(dotnetfeed-storage-access-key-1)'
+ /p:BARBuildId=$(BARBuildId)
+ /p:MaestroApiEndpoint='$(MaestroApiEndPoint)'
+ /p:BuildAssetRegistryToken='$(MaestroApiAccessToken)'
+ /p:ManifestsBasePath='$(Build.ArtifactStagingDirectory)/AssetManifests/'
+ /p:BlobBasePath='$(Build.ArtifactStagingDirectory)/BlobArtifacts/'
+ /p:PackageBasePath='$(Build.ArtifactStagingDirectory)/PackageArtifacts/'
+ /p:Configuration=Release
+ /p:PublishInstallersAndChecksums=${{ parameters.publishInstallersAndChecksums }}
+ /p:ChecksumsTargetStaticFeed=$(InternalChecksumsBlobFeedUrl)
+ /p:ChecksumsAzureAccountKey=$(InternalChecksumsBlobFeedKey)
+ /p:InstallersTargetStaticFeed=$(InternalInstallersBlobFeedUrl)
+ /p:InstallersAzureAccountKey=$(InternalInstallersBlobFeedKey)
+ /p:AzureDevOpsStaticShippingFeed='${{ parameters.shippingFeed }}'
+ /p:AzureDevOpsStaticShippingFeedKey='$(dn-bot-dnceng-artifact-feeds-rw)'
+ /p:AzureDevOpsStaticTransportFeed='${{ parameters.transportFeed }}'
+ /p:AzureDevOpsStaticTransportFeedKey='$(dn-bot-dnceng-artifact-feeds-rw)'
+ /p:AzureDevOpsStaticSymbolsFeed='${{ parameters.symbolsFeed }}'
+ /p:AzureDevOpsStaticSymbolsFeedKey='$(dn-bot-dnceng-artifact-feeds-rw)'
+ /p:PublishToMSDL=false
+ ${{ parameters.artifactsPublishingAdditionalParameters }}
+
+ - template: ../../steps/publish-logs.yml
+ parameters:
+ StageLabel: '${{ parameters.stageName }}'
+ JobLabel: 'AssetsPublishing'
+
+ - template: ../../steps/add-build-to-channel.yml
+ parameters:
+ ChannelId: ${{ parameters.channelId }}
diff --git a/eng/common/templates/post-build/channels/generic-public-channel.yml b/eng/common/templates/post-build/channels/generic-public-channel.yml
new file mode 100644
index 000000000..3220c6a4f
--- /dev/null
+++ b/eng/common/templates/post-build/channels/generic-public-channel.yml
@@ -0,0 +1,192 @@
+parameters:
+ BARBuildId: ''
+ PromoteToChannelIds: ''
+ artifactsPublishingAdditionalParameters: ''
+ dependsOn:
+ - Validate
+ publishInstallersAndChecksums: true
+ symbolPublishingAdditionalParameters: ''
+ stageName: ''
+ channelName: ''
+ channelId: ''
+ transportFeed: ''
+ shippingFeed: ''
+ symbolsFeed: ''
+ # If the channel name is empty, no links will be generated
+ akaMSChannelName: ''
+
+stages:
+- stage: ${{ parameters.stageName }}
+ dependsOn: ${{ parameters.dependsOn }}
+ variables:
+ - template: ../common-variables.yml
+ displayName: ${{ parameters.channelName }} Publishing
+ jobs:
+ - template: ../setup-maestro-vars.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+
+ - job: publish_symbols
+ displayName: Symbol Publishing
+ dependsOn: setupMaestroVars
+ condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.TargetChannels'], format('[{0}]', ${{ parameters.channelId }} ))
+ variables:
+ - group: DotNet-Symbol-Server-Pats
+ - name: AzDOProjectName
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ]
+ - name: AzDOPipelineId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ]
+ - name: AzDOBuildId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ]
+ pool:
+ vmImage: 'windows-2019'
+ steps:
+ - script: echo "##vso[task.logissue type=warning]Going forward, v2 Arcade publishing is no longer supported. Please read https://github.com/dotnet/arcade/blob/main/Documentation/CorePackages/Publishing.md for details, then contact dnceng if you have further questions."
+ displayName: Warn about v2 Arcade Publishing Usage
+
+ - task: DownloadBuildArtifacts@0
+ displayName: Download Build Assets
+ continueOnError: true
+ inputs:
+ buildType: specific
+ buildVersionToDownload: specific
+ project: $(AzDOProjectName)
+ pipeline: $(AzDOPipelineId)
+ buildId: $(AzDOBuildId)
+ downloadType: 'specific'
+ itemPattern: |
+ PdbArtifacts/**
+ BlobArtifacts/**
+ downloadPath: '$(Build.ArtifactStagingDirectory)'
+ checkDownloadedFiles: true
+
+ # This is necessary whenever we want to publish/restore to an AzDO private feed
+ # Since sdk-task.ps1 tries to restore packages we need to do this authentication here
+ # otherwise it'll complain about accessing a private feed.
+ - task: NuGetAuthenticate@0
+ displayName: 'Authenticate to AzDO Feeds'
+
+ - task: PowerShell@2
+ displayName: Enable cross-org publishing
+ inputs:
+ filePath: eng\common\enable-cross-org-publishing.ps1
+ arguments: -token $(dn-bot-dnceng-artifact-feeds-rw)
+
+ - task: PowerShell@2
+ displayName: Publish
+ inputs:
+ filePath: eng\common\sdk-task.ps1
+ arguments: -task PublishToSymbolServers -restore -msbuildEngine dotnet
+ /p:DotNetSymbolServerTokenMsdl=$(microsoft-symbol-server-pat)
+ /p:DotNetSymbolServerTokenSymWeb=$(symweb-symbol-server-pat)
+ /p:PDBArtifactsDirectory='$(Build.ArtifactStagingDirectory)/PDBArtifacts/'
+ /p:BlobBasePath='$(Build.ArtifactStagingDirectory)/BlobArtifacts/'
+ /p:SymbolPublishingExclusionsFile='$(Build.SourcesDirectory)/eng/SymbolPublishingExclusionsFile.txt'
+ /p:Configuration=Release
+ ${{ parameters.symbolPublishingAdditionalParameters }}
+
+ - template: ../../steps/publish-logs.yml
+ parameters:
+ StageLabel: '${{ parameters.stageName }}'
+ JobLabel: 'SymbolPublishing'
+
+ - job: publish_assets
+ displayName: Publish Assets
+ dependsOn: setupMaestroVars
+ timeoutInMinutes: 120
+ variables:
+ - name: BARBuildId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ]
+ - name: IsStableBuild
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.IsStableBuild'] ]
+ - name: AzDOProjectName
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ]
+ - name: AzDOPipelineId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ]
+ - name: AzDOBuildId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ]
+ - name: ArtifactsCategory
+ value: ${{ coalesce(variables._DotNetArtifactsCategory, '.NETCore') }}
+ condition: contains(dependencies.setupMaestroVars.outputs['setReleaseVars.TargetChannels'], format('[{0}]', ${{ parameters.channelId }} ))
+ pool:
+ vmImage: 'windows-2019'
+ steps:
+ - script: echo "##vso[task.logissue type=warning]Going forward, v2 Arcade publishing is no longer supported. Please read https://github.com/dotnet/arcade/blob/main/Documentation/CorePackages/Publishing.md for details, then contact dnceng if you have further questions."
+ displayName: Warn about v2 Arcade Publishing Usage
+
+ - task: DownloadBuildArtifacts@0
+ displayName: Download Build Assets
+ continueOnError: true
+ inputs:
+ buildType: specific
+ buildVersionToDownload: specific
+ project: $(AzDOProjectName)
+ pipeline: $(AzDOPipelineId)
+ buildId: $(AzDOBuildId)
+ downloadType: 'specific'
+ itemPattern: |
+ PackageArtifacts/**
+ BlobArtifacts/**
+ AssetManifests/**
+ downloadPath: '$(Build.ArtifactStagingDirectory)'
+ checkDownloadedFiles: true
+
+ - task: NuGetToolInstaller@1
+ displayName: 'Install NuGet.exe'
+
+ # This is necessary whenever we want to publish/restore to an AzDO private feed
+ - task: NuGetAuthenticate@0
+ displayName: 'Authenticate to AzDO Feeds'
+
+ - task: PowerShell@2
+ displayName: Enable cross-org publishing
+ inputs:
+ filePath: eng\common\enable-cross-org-publishing.ps1
+ arguments: -token $(dn-bot-dnceng-artifact-feeds-rw)
+
+ - task: PowerShell@2
+ displayName: Publish Assets
+ inputs:
+ filePath: eng\common\sdk-task.ps1
+ arguments: -task PublishArtifactsInManifest -restore -msbuildEngine dotnet
+ /p:PublishingInfraVersion=2
+ /p:ArtifactsCategory=$(ArtifactsCategory)
+ /p:IsStableBuild=$(IsStableBuild)
+ /p:IsInternalBuild=$(IsInternalBuild)
+ /p:RepositoryName=$(Build.Repository.Name)
+ /p:CommitSha=$(Build.SourceVersion)
+ /p:NugetPath=$(NuGetExeToolPath)
+ /p:AzdoTargetFeedPAT='$(dn-bot-dnceng-universal-packages-rw)'
+ /p:AzureStorageTargetFeedPAT='$(dotnetfeed-storage-access-key-1)'
+ /p:BARBuildId=$(BARBuildId)
+ /p:MaestroApiEndpoint='$(MaestroApiEndPoint)'
+ /p:BuildAssetRegistryToken='$(MaestroApiAccessToken)'
+ /p:ManifestsBasePath='$(Build.ArtifactStagingDirectory)/AssetManifests/'
+ /p:BlobBasePath='$(Build.ArtifactStagingDirectory)/BlobArtifacts/'
+ /p:PackageBasePath='$(Build.ArtifactStagingDirectory)/PackageArtifacts/'
+ /p:Configuration=Release
+ /p:PublishInstallersAndChecksums=${{ parameters.publishInstallersAndChecksums }}
+ /p:InstallersTargetStaticFeed=$(InstallersBlobFeedUrl)
+ /p:InstallersAzureAccountKey=$(dotnetcli-storage-key)
+ /p:ChecksumsTargetStaticFeed=$(ChecksumsBlobFeedUrl)
+ /p:ChecksumsAzureAccountKey=$(dotnetclichecksums-storage-key)
+ /p:AzureDevOpsStaticShippingFeed='${{ parameters.shippingFeed }}'
+ /p:AzureDevOpsStaticShippingFeedKey='$(dn-bot-dnceng-artifact-feeds-rw)'
+ /p:AzureDevOpsStaticTransportFeed='${{ parameters.transportFeed }}'
+ /p:AzureDevOpsStaticTransportFeedKey='$(dn-bot-dnceng-artifact-feeds-rw)'
+ /p:AzureDevOpsStaticSymbolsFeed='${{ parameters.symbolsFeed }}'
+ /p:AzureDevOpsStaticSymbolsFeedKey='$(dn-bot-dnceng-artifact-feeds-rw)'
+ /p:LatestLinkShortUrlPrefix=dotnet/'${{ parameters.akaMSChannelName }}'
+ /p:AkaMSClientId=$(akams-client-id)
+ /p:AkaMSClientSecret=$(akams-client-secret)
+ ${{ parameters.artifactsPublishingAdditionalParameters }}
+
+ - template: ../../steps/publish-logs.yml
+ parameters:
+ StageLabel: '${{ parameters.stageName }}'
+ JobLabel: 'AssetsPublishing'
+
+ - template: ../../steps/add-build-to-channel.yml
+ parameters:
+ ChannelId: ${{ parameters.channelId }}
diff --git a/eng/common/templates/post-build/common-variables.yml b/eng/common/templates/post-build/common-variables.yml
new file mode 100644
index 000000000..c99fd7503
--- /dev/null
+++ b/eng/common/templates/post-build/common-variables.yml
@@ -0,0 +1,99 @@
+variables:
+ - group: AzureDevOps-Artifact-Feeds-Pats
+ - group: DotNet-Blob-Feed
+ - group: DotNet-DotNetCli-Storage
+ - group: DotNet-MSRC-Storage
+ - group: Publish-Build-Assets
+
+ # .NET Core 3.1 Dev
+ - name: PublicDevRelease_31_Channel_Id
+ value: 128
+
+ # .NET 5 Dev
+ - name: Net_5_Dev_Channel_Id
+ value: 131
+
+ # .NET Eng - Validation
+ - name: Net_Eng_Validation_Channel_Id
+ value: 9
+
+ # .NET Eng - Latest
+ - name: Net_Eng_Latest_Channel_Id
+ value: 2
+
+ # .NET 3 Eng - Validation
+ - name: NET_3_Eng_Validation_Channel_Id
+ value: 390
+
+ # .NET 3 Eng
+ - name: NetCore_3_Tools_Channel_Id
+ value: 344
+
+ # .NET Core 3.0 Internal Servicing
+ - name: InternalServicing_30_Channel_Id
+ value: 184
+
+ # .NET Core 3.0 Release
+ - name: PublicRelease_30_Channel_Id
+ value: 19
+
+ # .NET Core 3.1 Release
+ - name: PublicRelease_31_Channel_Id
+ value: 129
+
+ # General Testing
+ - name: GeneralTesting_Channel_Id
+ value: 529
+
+ # .NET Core 3.1 Blazor Features
+ - name: NetCore_31_Blazor_Features_Channel_Id
+ value: 531
+
+ # .NET Core Experimental
+ - name: NetCore_Experimental_Channel_Id
+ value: 562
+
+ # Whether the build is internal or not
+ - name: IsInternalBuild
+ value: ${{ and(ne(variables['System.TeamProject'], 'public'), contains(variables['Build.SourceBranch'], 'internal')) }}
+
+ # Default Maestro++ API Endpoint and API Version
+ - name: MaestroApiEndPoint
+ value: "https://maestro-prod.westus2.cloudapp.azure.com"
+ - name: MaestroApiAccessToken
+ value: $(MaestroAccessToken)
+ - name: MaestroApiVersion
+ value: "2020-02-20"
+
+ - name: SourceLinkCLIVersion
+ value: 3.0.0
+ - name: SymbolToolVersion
+ value: 1.0.1
+
+ # Feed Configurations
+ # These should include the suffix "/index.json"
+
+ # Default locations for Installers and checksums
+ # Public Locations
+ - name: ChecksumsBlobFeedUrl
+ value: https://dotnetclichecksums.blob.core.windows.net/dotnet/index.json
+ - name: InstallersBlobFeedUrl
+ value: https://dotnetcli.blob.core.windows.net/dotnet/index.json
+
+ # Private Locations
+ - name: InternalChecksumsBlobFeedUrl
+ value: https://dotnetclichecksumsmsrc.blob.core.windows.net/dotnet/index.json
+ - name: InternalChecksumsBlobFeedKey
+ value: $(dotnetclichecksumsmsrc-storage-key)
+
+ - name: InternalInstallersBlobFeedUrl
+ value: https://dotnetclimsrc.blob.core.windows.net/dotnet/index.json
+ - name: InternalInstallersBlobFeedKey
+ value: $(dotnetclimsrc-access-key)
+
+ # Skip component governance and codesign validation for SDL. These jobs
+ # create no content.
+ - name: skipComponentGovernanceDetection
+ value: true
+ - name: runCodesignValidationInjection
+ value: false
diff --git a/eng/common/templates/post-build/post-build.yml b/eng/common/templates/post-build/post-build.yml
new file mode 100644
index 000000000..4f79cf0f3
--- /dev/null
+++ b/eng/common/templates/post-build/post-build.yml
@@ -0,0 +1,589 @@
+parameters:
+ # Which publishing infra should be used. THIS SHOULD MATCH THE VERSION ON THE BUILD MANIFEST.
+ # Publishing V2 accepts optionally outlining the publishing stages - default is inline.
+ # Publishing V3 DOES NOT accept inlining the publishing stages.
+ publishingInfraVersion: 2
+ # When set to true the publishing templates from the repo will be used
+ # otherwise Darc add-build-to-channel will be used to trigger the promotion pipeline
+ inline: true
+
+ # Only used if inline==false. When set to true will stall the current build until
+ # the Promotion Pipeline build finishes. Otherwise, the current build will continue
+ # execution concurrently with the promotion build.
+ waitPublishingFinish: true
+
+ BARBuildId: ''
+ PromoteToChannelIds: ''
+
+ enableSourceLinkValidation: false
+ enableSigningValidation: true
+ enableSymbolValidation: false
+ enableNugetValidation: true
+ publishInstallersAndChecksums: true
+ SDLValidationParameters:
+ enable: false
+ continueOnError: false
+ params: ''
+ artifactNames: ''
+ downloadArtifacts: true
+
+ # These parameters let the user customize the call to sdk-task.ps1 for publishing
+ # symbols & general artifacts as well as for signing validation
+ symbolPublishingAdditionalParameters: ''
+ artifactsPublishingAdditionalParameters: ''
+ signingValidationAdditionalParameters: ''
+
+ # Which stages should finish execution before post-build stages start
+ validateDependsOn:
+ - build
+ publishDependsOn:
+ - Validate
+
+ # Channel ID's instantiated in this file.
+ # When adding a new channel implementation the call to `check-channel-consistency.ps1`
+ # needs to be updated with the new channel ID
+ NetEngLatestChannelId: 2
+ NetEngValidationChannelId: 9
+ NetDev5ChannelId: 131
+ NetDev6ChannelId: 1296
+ GeneralTestingChannelId: 529
+ NETCoreToolingDevChannelId: 548
+ NETCoreToolingReleaseChannelId: 549
+ NETInternalToolingChannelId: 551
+ NETCoreExperimentalChannelId: 562
+ NetEngServicesIntChannelId: 678
+ NetEngServicesProdChannelId: 679
+ NetCoreSDK313xxChannelId: 759
+ NetCoreSDK313xxInternalChannelId: 760
+ NetCoreSDK314xxChannelId: 921
+ NetCoreSDK314xxInternalChannelId: 922
+ VS166ChannelId: 1010
+ VS167ChannelId: 1011
+ VS168ChannelId: 1154
+ VSMasterChannelId: 1012
+ VS169ChannelId: 1473
+ VS1610ChannelId: 1692
+
+stages:
+- ${{ if or(and(le(parameters.publishingInfraVersion, 2), eq(parameters.inline, 'true')), eq( parameters.enableNugetValidation, 'true'), eq(parameters.enableSigningValidation, 'true'), eq(parameters.enableSourceLinkValidation, 'true'), eq(parameters.SDLValidationParameters.enable, 'true')) }}:
+ - stage: Validate
+ dependsOn: ${{ parameters.validateDependsOn }}
+ displayName: Validate Build Assets
+ variables:
+ - template: common-variables.yml
+ jobs:
+ - template: setup-maestro-vars.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+
+ - ${{ if and(le(parameters.publishingInfraVersion, 2), eq(parameters.inline, 'true')) }}:
+ - job:
+ displayName: Post-build Checks
+ dependsOn: setupMaestroVars
+ variables:
+ - name: TargetChannels
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.TargetChannels'] ]
+ pool:
+ vmImage: 'windows-2019'
+ steps:
+ - task: PowerShell@2
+ displayName: Maestro Channels Consistency
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/post-build/check-channel-consistency.ps1
+ arguments: -PromoteToChannels "$(TargetChannels)"
+ -AvailableChannelIds ${{parameters.NetEngLatestChannelId}},${{parameters.NetEngValidationChannelId}},${{parameters.NetDev5ChannelId}},${{parameters.NetDev6ChannelId}},${{parameters.GeneralTestingChannelId}},${{parameters.NETCoreToolingDevChannelId}},${{parameters.NETCoreToolingReleaseChannelId}},${{parameters.NETInternalToolingChannelId}},${{parameters.NETCoreExperimentalChannelId}},${{parameters.NetEngServicesIntChannelId}},${{parameters.NetEngServicesProdChannelId}},${{parameters.NetCoreSDK313xxChannelId}},${{parameters.NetCoreSDK313xxInternalChannelId}},${{parameters.NetCoreSDK314xxChannelId}},${{parameters.NetCoreSDK314xxInternalChannelId}},${{parameters.VS166ChannelId}},${{parameters.VS167ChannelId}},${{parameters.VS168ChannelId}},${{parameters.VSMasterChannelId}},${{parameters.VS169ChannelId}},${{parameters.VS1610ChannelId}}
+
+ - job:
+ displayName: NuGet Validation
+ dependsOn: setupMaestroVars
+ condition: eq( ${{ parameters.enableNugetValidation }}, 'true')
+ pool:
+ vmImage: 'windows-2019'
+ variables:
+ - name: AzDOProjectName
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ]
+ - name: AzDOPipelineId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ]
+ - name: AzDOBuildId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ]
+ steps:
+ - task: DownloadBuildArtifacts@0
+ displayName: Download Package Artifacts
+ inputs:
+ buildType: specific
+ buildVersionToDownload: specific
+ project: $(AzDOProjectName)
+ pipeline: $(AzDOPipelineId)
+ buildId: $(AzDOBuildId)
+ artifactName: PackageArtifacts
+ checkDownloadedFiles: true
+
+ - task: PowerShell@2
+ displayName: Validate
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/post-build/nuget-validation.ps1
+ arguments: -PackagesPath $(Build.ArtifactStagingDirectory)/PackageArtifacts/
+ -ToolDestinationPath $(Agent.BuildDirectory)/Extract/
+
+ - job:
+ displayName: Signing Validation
+ dependsOn: setupMaestroVars
+ condition: and( eq( ${{ parameters.enableSigningValidation }}, 'true'), ne( variables['PostBuildSign'], 'true'))
+ variables:
+ - template: common-variables.yml
+ - name: AzDOProjectName
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ]
+ - name: AzDOPipelineId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ]
+ - name: AzDOBuildId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ]
+ pool:
+ vmImage: 'windows-2019'
+ steps:
+ - task: DownloadBuildArtifacts@0
+ displayName: Download Package Artifacts
+ inputs:
+ buildType: specific
+ buildVersionToDownload: specific
+ project: $(AzDOProjectName)
+ pipeline: $(AzDOPipelineId)
+ buildId: $(AzDOBuildId)
+ artifactName: PackageArtifacts
+ checkDownloadedFiles: true
+ itemPattern: |
+ **
+ !**/Microsoft.SourceBuild.Intermediate.*.nupkg
+
+ # This is necessary whenever we want to publish/restore to an AzDO private feed
+ # Since sdk-task.ps1 tries to restore packages we need to do this authentication here
+ # otherwise it'll complain about accessing a private feed.
+ - task: NuGetAuthenticate@0
+ displayName: 'Authenticate to AzDO Feeds'
+
+ - task: PowerShell@2
+ displayName: Enable cross-org publishing
+ inputs:
+ filePath: eng\common\enable-cross-org-publishing.ps1
+ arguments: -token $(dn-bot-dnceng-artifact-feeds-rw)
+
+ # Signing validation will optionally work with the buildmanifest file which is downloaded from
+ # Azure DevOps above.
+ - task: PowerShell@2
+ displayName: Validate
+ inputs:
+ filePath: eng\common\sdk-task.ps1
+ arguments: -task SigningValidation -restore -msbuildEngine vs
+ /p:PackageBasePath='$(Build.ArtifactStagingDirectory)/PackageArtifacts'
+ /p:SignCheckExclusionsFile='$(Build.SourcesDirectory)/eng/SignCheckExclusionsFile.txt'
+ ${{ parameters.signingValidationAdditionalParameters }}
+
+ - template: ../steps/publish-logs.yml
+ parameters:
+ StageLabel: 'Validation'
+ JobLabel: 'Signing'
+
+ - job:
+ displayName: SourceLink Validation
+ dependsOn: setupMaestroVars
+ condition: eq( ${{ parameters.enableSourceLinkValidation }}, 'true')
+ variables:
+ - template: common-variables.yml
+ - name: AzDOProjectName
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ]
+ - name: AzDOPipelineId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ]
+ - name: AzDOBuildId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ]
+ pool:
+ vmImage: 'windows-2019'
+ steps:
+ - task: DownloadBuildArtifacts@0
+ displayName: Download Blob Artifacts
+ inputs:
+ buildType: specific
+ buildVersionToDownload: specific
+ project: $(AzDOProjectName)
+ pipeline: $(AzDOPipelineId)
+ buildId: $(AzDOBuildId)
+ artifactName: BlobArtifacts
+ checkDownloadedFiles: true
+
+ - task: PowerShell@2
+ displayName: Validate
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/post-build/sourcelink-validation.ps1
+ arguments: -InputPath $(Build.ArtifactStagingDirectory)/BlobArtifacts/
+ -ExtractPath $(Agent.BuildDirectory)/Extract/
+ -GHRepoName $(Build.Repository.Name)
+ -GHCommit $(Build.SourceVersion)
+ -SourcelinkCliVersion $(SourceLinkCLIVersion)
+ continueOnError: true
+
+ - template: /eng/common/templates/job/execute-sdl.yml
+ parameters:
+ enable: ${{ parameters.SDLValidationParameters.enable }}
+ dependsOn: setupMaestroVars
+ additionalParameters: ${{ parameters.SDLValidationParameters.params }}
+ continueOnError: ${{ parameters.SDLValidationParameters.continueOnError }}
+ artifactNames: ${{ parameters.SDLValidationParameters.artifactNames }}
+ downloadArtifacts: ${{ parameters.SDLValidationParameters.downloadArtifacts }}
+
+- ${{ if or(ge(parameters.publishingInfraVersion, 3), eq(parameters.inline, 'false')) }}:
+ - stage: publish_using_darc
+ ${{ if or(eq(parameters.enableNugetValidation, 'true'), eq(parameters.enableSigningValidation, 'true'), eq(parameters.enableSourceLinkValidation, 'true'), eq(parameters.SDLValidationParameters.enable, 'true')) }}:
+ dependsOn: ${{ parameters.publishDependsOn }}
+ ${{ if and(ne(parameters.enableNugetValidation, 'true'), ne(parameters.enableSigningValidation, 'true'), ne(parameters.enableSourceLinkValidation, 'true'), ne(parameters.SDLValidationParameters.enable, 'true')) }}:
+ dependsOn: ${{ parameters.validateDependsOn }}
+ displayName: Publish using Darc
+ variables:
+ - template: common-variables.yml
+ jobs:
+ - template: setup-maestro-vars.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+
+ - job:
+ displayName: Publish Using Darc
+ dependsOn: setupMaestroVars
+ timeoutInMinutes: 120
+ variables:
+ - name: BARBuildId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ]
+ pool:
+ vmImage: 'windows-2019'
+ steps:
+ - task: PowerShell@2
+ displayName: Publish Using Darc
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/post-build/publish-using-darc.ps1
+ arguments: -BuildId $(BARBuildId)
+ -PublishingInfraVersion ${{ parameters.PublishingInfraVersion }}
+ -AzdoToken '$(publishing-dnceng-devdiv-code-r-build-re)'
+ -MaestroToken '$(MaestroApiAccessToken)'
+ -WaitPublishingFinish ${{ parameters.waitPublishingFinish }}
+ -PublishInstallersAndChecksums ${{ parameters.publishInstallersAndChecksums }}
+ -ArtifactsPublishingAdditionalParameters '${{ parameters.artifactsPublishingAdditionalParameters }}'
+ -SymbolPublishingAdditionalParameters '${{ parameters.symbolPublishingAdditionalParameters }}'
+
+- ${{ if and(le(parameters.publishingInfraVersion, 2), eq(parameters.inline, 'true')) }}:
+ - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'NetCore_Dev5_Publish'
+ channelName: '.NET 5 Dev'
+ akaMSChannelName: 'net5/dev'
+ channelId: ${{ parameters.NetDev5ChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5-transport/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5-symbols/nuget/v3/index.json'
+
+ - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'NetCore_Dev6_Publish'
+ channelName: '.NET 6 Dev'
+ akaMSChannelName: 'net6/dev'
+ channelId: ${{ parameters.NetDev6ChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet6-transport/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet6/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet6-symbols/nuget/v3/index.json'
+
+ - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'Net_Eng_Latest_Publish'
+ channelName: '.NET Eng - Latest'
+ akaMSChannelName: 'eng/daily'
+ channelId: ${{ parameters.NetEngLatestChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng-symbols/nuget/v3/index.json'
+
+ - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'Net_Eng_Validation_Publish'
+ channelName: '.NET Eng - Validation'
+ akaMSChannelName: 'eng/validation'
+ channelId: ${{ parameters.NetEngValidationChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng-symbols/nuget/v3/index.json'
+
+ - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'General_Testing_Publish'
+ channelName: 'General Testing'
+ akaMSChannelName: 'generaltesting'
+ channelId: ${{ parameters.GeneralTestingChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/general-testing/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/general-testing/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/general-testing-symbols/nuget/v3/index.json'
+
+ - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'NETCore_Tooling_Dev_Publishing'
+ channelName: '.NET Core Tooling Dev'
+ channelId: ${{ parameters.NETCoreToolingDevChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-symbols/nuget/v3/index.json'
+
+ - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'NETCore_Tooling_Release_Publishing'
+ channelName: '.NET Core Tooling Release'
+ channelId: ${{ parameters.NETCoreToolingReleaseChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-symbols/nuget/v3/index.json'
+
+ - template: \eng\common\templates\post-build\channels\generic-internal-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'NET_Internal_Tooling_Publishing'
+ channelName: '.NET Internal Tooling'
+ channelId: ${{ parameters.NETInternalToolingChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet-tools-internal/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet-tools-internal/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet-tools-internal-symbols/nuget/v3/index.json'
+
+ - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'NETCore_Experimental_Publishing'
+ channelName: '.NET Core Experimental'
+ channelId: ${{ parameters.NETCoreExperimentalChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-experimental/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-experimental/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-experimental-symbols/nuget/v3/index.json'
+
+ - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'Net_Eng_Services_Int_Publish'
+ channelName: '.NET Eng Services - Int'
+ channelId: ${{ parameters.NetEngServicesIntChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng-symbols/nuget/v3/index.json'
+
+ - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'Net_Eng_Services_Prod_Publish'
+ channelName: '.NET Eng Services - Prod'
+ channelId: ${{ parameters.NetEngServicesProdChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng-symbols/nuget/v3/index.json'
+
+ - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'NETCore_SDK_314xx_Publishing'
+ channelName: '.NET Core SDK 3.1.4xx'
+ channelId: ${{ parameters.NetCoreSDK314xxChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet3.1-transport/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet3.1/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet3.1-symbols/nuget/v3/index.json'
+
+ - template: \eng\common\templates\post-build\channels\generic-internal-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'NETCore_SDK_314xx_Internal_Publishing'
+ channelName: '.NET Core SDK 3.1.4xx Internal'
+ channelId: ${{ parameters.NetCoreSDK314xxInternalChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal-transport/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal-symbols/nuget/v3/index.json'
+
+ - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'NETCore_SDK_313xx_Publishing'
+ channelName: '.NET Core SDK 3.1.3xx'
+ channelId: ${{ parameters.NetCoreSDK313xxChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet3.1-transport/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet3.1/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet3.1-symbols/nuget/v3/index.json'
+
+ - template: \eng\common\templates\post-build\channels\generic-internal-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'NETCore_SDK_313xx_Internal_Publishing'
+ channelName: '.NET Core SDK 3.1.3xx Internal'
+ channelId: ${{ parameters.NetCoreSDK313xxInternalChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal-transport/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal-symbols/nuget/v3/index.json'
+
+ - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'VS16_6_Publishing'
+ channelName: 'VS 16.6'
+ channelId: ${{ parameters.VS166ChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-transport/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-symbols/nuget/v3/index.json'
+
+ - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'VS16_7_Publishing'
+ channelName: 'VS 16.7'
+ channelId: ${{ parameters.VS167ChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-transport/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-symbols/nuget/v3/index.json'
+
+ - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'VS16_8_Publishing'
+ channelName: 'VS 16.8'
+ channelId: ${{ parameters.VS168ChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-transport/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-symbols/nuget/v3/index.json'
+
+ - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'VS_Master_Publishing'
+ channelName: 'VS Master'
+ channelId: ${{ parameters.VSMasterChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-transport/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-symbols/nuget/v3/index.json'
+
+ - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'VS_16_9_Publishing'
+ channelName: 'VS 16.9'
+ channelId: ${{ parameters.VS169ChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-transport/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-symbols/nuget/v3/index.json'
+
+ - template: \eng\common\templates\post-build\channels\generic-public-channel.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'VS_16_10_Publishing'
+ channelName: 'VS 16.10'
+ channelId: ${{ parameters.VS1610ChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-transport/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools-symbols/nuget/v3/index.json'
diff --git a/eng/common/templates/post-build/setup-maestro-vars.yml b/eng/common/templates/post-build/setup-maestro-vars.yml
new file mode 100644
index 000000000..4a22b2e6f
--- /dev/null
+++ b/eng/common/templates/post-build/setup-maestro-vars.yml
@@ -0,0 +1,78 @@
+parameters:
+ BARBuildId: ''
+ PromoteToChannelIds: ''
+
+jobs:
+- job: setupMaestroVars
+ displayName: Setup Maestro Vars
+ variables:
+ - template: common-variables.yml
+ pool:
+ vmImage: 'windows-2019'
+ steps:
+ - checkout: none
+
+ - ${{ if eq(coalesce(parameters.PromoteToChannelIds, 0), 0) }}:
+ - task: DownloadBuildArtifacts@0
+ displayName: Download Release Configs
+ inputs:
+ buildType: current
+ artifactName: ReleaseConfigs
+ checkDownloadedFiles: true
+
+ - task: PowerShell@2
+ name: setReleaseVars
+ displayName: Set Release Configs Vars
+ inputs:
+ targetType: inline
+ script: |
+ try {
+ if (!$Env:PromoteToMaestroChannels -or $Env:PromoteToMaestroChannels.Trim() -eq '') {
+ $Content = Get-Content $(Build.StagingDirectory)/ReleaseConfigs/ReleaseConfigs.txt
+
+ $BarId = $Content | Select -Index 0
+ $Channels = $Content | Select -Index 1
+ $IsStableBuild = $Content | Select -Index 2
+
+ $AzureDevOpsProject = $Env:System_TeamProject
+ $AzureDevOpsBuildDefinitionId = $Env:System_DefinitionId
+ $AzureDevOpsBuildId = $Env:Build_BuildId
+ }
+ else {
+ $buildApiEndpoint = "${Env:MaestroApiEndPoint}/api/builds/${Env:BARBuildId}?api-version=${Env:MaestroApiVersion}"
+
+ $apiHeaders = New-Object 'System.Collections.Generic.Dictionary[[String],[String]]'
+ $apiHeaders.Add('Accept', 'application/json')
+ $apiHeaders.Add('Authorization',"Bearer ${Env:MAESTRO_API_TOKEN}")
+
+ $buildInfo = try { Invoke-WebRequest -Method Get -Uri $buildApiEndpoint -Headers $apiHeaders | ConvertFrom-Json } catch { Write-Host "Error: $_" }
+
+ $BarId = $Env:BARBuildId
+ $Channels = $Env:PromoteToMaestroChannels -split ","
+ $Channels = $Channels -join "]["
+ $Channels = "[$Channels]"
+
+ $IsStableBuild = $buildInfo.stable
+ $AzureDevOpsProject = $buildInfo.azureDevOpsProject
+ $AzureDevOpsBuildDefinitionId = $buildInfo.azureDevOpsBuildDefinitionId
+ $AzureDevOpsBuildId = $buildInfo.azureDevOpsBuildId
+ }
+
+ Write-Host "##vso[task.setvariable variable=BARBuildId;isOutput=true]$BarId"
+ Write-Host "##vso[task.setvariable variable=TargetChannels;isOutput=true]$Channels"
+ Write-Host "##vso[task.setvariable variable=IsStableBuild;isOutput=true]$IsStableBuild"
+
+ Write-Host "##vso[task.setvariable variable=AzDOProjectName;isOutput=true]$AzureDevOpsProject"
+ Write-Host "##vso[task.setvariable variable=AzDOPipelineId;isOutput=true]$AzureDevOpsBuildDefinitionId"
+ Write-Host "##vso[task.setvariable variable=AzDOBuildId;isOutput=true]$AzureDevOpsBuildId"
+ }
+ catch {
+ Write-Host $_
+ Write-Host $_.Exception
+ Write-Host $_.ScriptStackTrace
+ exit 1
+ }
+ env:
+ MAESTRO_API_TOKEN: $(MaestroApiAccessToken)
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToMaestroChannels: ${{ parameters.PromoteToChannelIds }}
diff --git a/eng/common/templates/post-build/trigger-subscription.yml b/eng/common/templates/post-build/trigger-subscription.yml
new file mode 100644
index 000000000..da669030d
--- /dev/null
+++ b/eng/common/templates/post-build/trigger-subscription.yml
@@ -0,0 +1,13 @@
+parameters:
+ ChannelId: 0
+
+steps:
+- task: PowerShell@2
+ displayName: Triggering subscriptions
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/post-build/trigger-subscriptions.ps1
+ arguments: -SourceRepo $(Build.Repository.Uri)
+ -ChannelId ${{ parameters.ChannelId }}
+ -MaestroApiAccessToken $(MaestroAccessToken)
+ -MaestroApiEndPoint $(MaestroApiEndPoint)
+ -MaestroApiVersion $(MaestroApiVersion)
diff --git a/eng/common/templates/steps/add-build-to-channel.yml b/eng/common/templates/steps/add-build-to-channel.yml
new file mode 100644
index 000000000..f67a210d6
--- /dev/null
+++ b/eng/common/templates/steps/add-build-to-channel.yml
@@ -0,0 +1,13 @@
+parameters:
+ ChannelId: 0
+
+steps:
+- task: PowerShell@2
+ displayName: Add Build to Channel
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/post-build/add-build-to-channel.ps1
+ arguments: -BuildId $(BARBuildId)
+ -ChannelId ${{ parameters.ChannelId }}
+ -MaestroApiAccessToken $(MaestroApiAccessToken)
+ -MaestroApiEndPoint $(MaestroApiEndPoint)
+ -MaestroApiVersion $(MaestroApiVersion)
diff --git a/eng/common/templates/steps/build-reason.yml b/eng/common/templates/steps/build-reason.yml
new file mode 100644
index 000000000..eba58109b
--- /dev/null
+++ b/eng/common/templates/steps/build-reason.yml
@@ -0,0 +1,12 @@
+# build-reason.yml
+# Description: runs steps if build.reason condition is valid. conditions is a string of valid build reasons
+# to include steps (',' separated).
+parameters:
+ conditions: ''
+ steps: []
+
+steps:
+ - ${{ if and( not(startsWith(parameters.conditions, 'not')), contains(parameters.conditions, variables['build.reason'])) }}:
+ - ${{ parameters.steps }}
+ - ${{ if and( startsWith(parameters.conditions, 'not'), not(contains(parameters.conditions, variables['build.reason']))) }}:
+ - ${{ parameters.steps }}
diff --git a/eng/common/templates/steps/publish-logs.yml b/eng/common/templates/steps/publish-logs.yml
new file mode 100644
index 000000000..88f238f36
--- /dev/null
+++ b/eng/common/templates/steps/publish-logs.yml
@@ -0,0 +1,23 @@
+parameters:
+ StageLabel: ''
+ JobLabel: ''
+
+steps:
+- task: Powershell@2
+ displayName: Prepare Binlogs to Upload
+ inputs:
+ targetType: inline
+ script: |
+ New-Item -ItemType Directory $(Build.SourcesDirectory)/PostBuildLogs/${{parameters.StageLabel}}/${{parameters.JobLabel}}/
+ Move-Item -Path $(Build.SourcesDirectory)/artifacts/log/Debug/* $(Build.SourcesDirectory)/PostBuildLogs/${{parameters.StageLabel}}/${{parameters.JobLabel}}/
+ continueOnError: true
+ condition: always()
+
+- task: PublishBuildArtifacts@1
+ displayName: Publish Logs
+ inputs:
+ PathtoPublish: '$(Build.SourcesDirectory)/PostBuildLogs'
+ PublishLocation: Container
+ ArtifactName: PostBuildLogs
+ continueOnError: true
+ condition: always()
diff --git a/eng/common/templates/steps/run-on-unix.yml b/eng/common/templates/steps/run-on-unix.yml
new file mode 100644
index 000000000..e1733814f
--- /dev/null
+++ b/eng/common/templates/steps/run-on-unix.yml
@@ -0,0 +1,7 @@
+parameters:
+ agentOs: ''
+ steps: []
+
+steps:
+- ${{ if ne(parameters.agentOs, 'Windows_NT') }}:
+ - ${{ parameters.steps }}
diff --git a/eng/common/templates/steps/run-on-windows.yml b/eng/common/templates/steps/run-on-windows.yml
new file mode 100644
index 000000000..73e7e9c27
--- /dev/null
+++ b/eng/common/templates/steps/run-on-windows.yml
@@ -0,0 +1,7 @@
+parameters:
+ agentOs: ''
+ steps: []
+
+steps:
+- ${{ if eq(parameters.agentOs, 'Windows_NT') }}:
+ - ${{ parameters.steps }}
diff --git a/eng/common/templates/steps/run-script-ifequalelse.yml b/eng/common/templates/steps/run-script-ifequalelse.yml
new file mode 100644
index 000000000..3d1242f55
--- /dev/null
+++ b/eng/common/templates/steps/run-script-ifequalelse.yml
@@ -0,0 +1,33 @@
+parameters:
+ # if parameter1 equals parameter 2, run 'ifScript' command, else run 'elsescript' command
+ parameter1: ''
+ parameter2: ''
+ ifScript: ''
+ elseScript: ''
+
+ # name of script step
+ name: Script
+
+ # display name of script step
+ displayName: If-Equal-Else Script
+
+ # environment
+ env: {}
+
+ # conditional expression for step execution
+ condition: ''
+
+steps:
+- ${{ if and(ne(parameters.ifScript, ''), eq(parameters.parameter1, parameters.parameter2)) }}:
+ - script: ${{ parameters.ifScript }}
+ name: ${{ parameters.name }}
+ displayName: ${{ parameters.displayName }}
+ env: ${{ parameters.env }}
+ condition: ${{ parameters.condition }}
+
+- ${{ if and(ne(parameters.elseScript, ''), ne(parameters.parameter1, parameters.parameter2)) }}:
+ - script: ${{ parameters.elseScript }}
+ name: ${{ parameters.name }}
+ displayName: ${{ parameters.displayName }}
+ env: ${{ parameters.env }}
+ condition: ${{ parameters.condition }}
\ No newline at end of file
diff --git a/eng/common/templates/steps/send-to-helix.yml b/eng/common/templates/steps/send-to-helix.yml
new file mode 100644
index 000000000..cd02ae160
--- /dev/null
+++ b/eng/common/templates/steps/send-to-helix.yml
@@ -0,0 +1,94 @@
+# Please remember to update the documentation if you make changes to these parameters!
+parameters:
+ HelixSource: 'pr/default' # required -- sources must start with pr/, official/, prodcon/, or agent/
+ HelixType: 'tests/default/' # required -- Helix telemetry which identifies what type of data this is; should include "test" for clarity and must end in '/'
+ HelixBuild: $(Build.BuildNumber) # required -- the build number Helix will use to identify this -- automatically set to the AzDO build number
+ HelixTargetQueues: '' # required -- semicolon delimited list of Helix queues to test on; see https://helix.dot.net/ for a list of queues
+ HelixAccessToken: '' # required -- access token to make Helix API requests; should be provided by the appropriate variable group
+ HelixConfiguration: '' # optional -- additional property attached to a job
+ HelixPreCommands: '' # optional -- commands to run before Helix work item execution
+ HelixPostCommands: '' # optional -- commands to run after Helix work item execution
+ WorkItemDirectory: '' # optional -- a payload directory to zip up and send to Helix; requires WorkItemCommand; incompatible with XUnitProjects
+ WorkItemCommand: '' # optional -- a command to execute on the payload; requires WorkItemDirectory; incompatible with XUnitProjects
+ WorkItemTimeout: '' # optional -- a timeout in TimeSpan.Parse-ready value (e.g. 00:02:00) for the work item command; requires WorkItemDirectory; incompatible with XUnitProjects
+ CorrelationPayloadDirectory: '' # optional -- a directory to zip up and send to Helix as a correlation payload
+ XUnitProjects: '' # optional -- semicolon delimited list of XUnitProjects to parse and send to Helix; requires XUnitRuntimeTargetFramework, XUnitPublishTargetFramework, XUnitRunnerVersion, and IncludeDotNetCli=true
+ XUnitWorkItemTimeout: '' # optional -- the workitem timeout in seconds for all workitems created from the xUnit projects specified by XUnitProjects
+ XUnitPublishTargetFramework: '' # optional -- framework to use to publish your xUnit projects
+ XUnitRuntimeTargetFramework: '' # optional -- framework to use for the xUnit console runner
+ XUnitRunnerVersion: '' # optional -- version of the xUnit nuget package you wish to use on Helix; required for XUnitProjects
+ IncludeDotNetCli: false # optional -- true will download a version of the .NET CLI onto the Helix machine as a correlation payload; requires DotNetCliPackageType and DotNetCliVersion
+ DotNetCliPackageType: '' # optional -- either 'sdk', 'runtime' or 'aspnetcore-runtime'; determines whether the sdk or runtime will be sent to Helix; see https://raw.githubusercontent.com/dotnet/core/main/release-notes/releases-index.json
+ DotNetCliVersion: '' # optional -- version of the CLI to send to Helix; based on this: https://raw.githubusercontent.com/dotnet/core/main/release-notes/releases-index.json
+ EnableXUnitReporter: false # optional -- true enables XUnit result reporting to Mission Control
+ WaitForWorkItemCompletion: true # optional -- true will make the task wait until work items have been completed and fail the build if work items fail. False is "fire and forget."
+ IsExternal: false # [DEPRECATED] -- doesn't do anything, jobs are external if HelixAccessToken is empty and Creator is set
+ HelixBaseUri: 'https://helix.dot.net/' # optional -- sets the Helix API base URI (allows targeting int)
+ Creator: '' # optional -- if the build is external, use this to specify who is sending the job
+ DisplayNamePrefix: 'Run Tests' # optional -- rename the beginning of the displayName of the steps in AzDO
+ condition: succeeded() # optional -- condition for step to execute; defaults to succeeded()
+ continueOnError: false # optional -- determines whether to continue the build if the step errors; defaults to false
+
+steps:
+ - powershell: 'powershell "$env:BUILD_SOURCESDIRECTORY\eng\common\msbuild.ps1 $env:BUILD_SOURCESDIRECTORY\eng\common\helixpublish.proj /restore /t:Test /bl:$env:BUILD_SOURCESDIRECTORY\artifacts\log\$env:BuildConfig\SendToHelix.binlog"'
+ displayName: ${{ parameters.DisplayNamePrefix }} (Windows)
+ env:
+ BuildConfig: $(_BuildConfig)
+ HelixSource: ${{ parameters.HelixSource }}
+ HelixType: ${{ parameters.HelixType }}
+ HelixBuild: ${{ parameters.HelixBuild }}
+ HelixConfiguration: ${{ parameters.HelixConfiguration }}
+ HelixTargetQueues: ${{ parameters.HelixTargetQueues }}
+ HelixAccessToken: ${{ parameters.HelixAccessToken }}
+ HelixPreCommands: ${{ parameters.HelixPreCommands }}
+ HelixPostCommands: ${{ parameters.HelixPostCommands }}
+ WorkItemDirectory: ${{ parameters.WorkItemDirectory }}
+ WorkItemCommand: ${{ parameters.WorkItemCommand }}
+ WorkItemTimeout: ${{ parameters.WorkItemTimeout }}
+ CorrelationPayloadDirectory: ${{ parameters.CorrelationPayloadDirectory }}
+ XUnitProjects: ${{ parameters.XUnitProjects }}
+ XUnitWorkItemTimeout: ${{ parameters.XUnitWorkItemTimeout }}
+ XUnitPublishTargetFramework: ${{ parameters.XUnitPublishTargetFramework }}
+ XUnitRuntimeTargetFramework: ${{ parameters.XUnitRuntimeTargetFramework }}
+ XUnitRunnerVersion: ${{ parameters.XUnitRunnerVersion }}
+ IncludeDotNetCli: ${{ parameters.IncludeDotNetCli }}
+ DotNetCliPackageType: ${{ parameters.DotNetCliPackageType }}
+ DotNetCliVersion: ${{ parameters.DotNetCliVersion }}
+ EnableXUnitReporter: ${{ parameters.EnableXUnitReporter }}
+ WaitForWorkItemCompletion: ${{ parameters.WaitForWorkItemCompletion }}
+ HelixBaseUri: ${{ parameters.HelixBaseUri }}
+ Creator: ${{ parameters.Creator }}
+ SYSTEM_ACCESSTOKEN: $(System.AccessToken)
+ condition: and(${{ parameters.condition }}, eq(variables['Agent.Os'], 'Windows_NT'))
+ continueOnError: ${{ parameters.continueOnError }}
+ - script: $BUILD_SOURCESDIRECTORY/eng/common/msbuild.sh $BUILD_SOURCESDIRECTORY/eng/common/helixpublish.proj /restore /t:Test /bl:$BUILD_SOURCESDIRECTORY/artifacts/log/$BuildConfig/SendToHelix.binlog
+ displayName: ${{ parameters.DisplayNamePrefix }} (Unix)
+ env:
+ BuildConfig: $(_BuildConfig)
+ HelixSource: ${{ parameters.HelixSource }}
+ HelixType: ${{ parameters.HelixType }}
+ HelixBuild: ${{ parameters.HelixBuild }}
+ HelixConfiguration: ${{ parameters.HelixConfiguration }}
+ HelixTargetQueues: ${{ parameters.HelixTargetQueues }}
+ HelixAccessToken: ${{ parameters.HelixAccessToken }}
+ HelixPreCommands: ${{ parameters.HelixPreCommands }}
+ HelixPostCommands: ${{ parameters.HelixPostCommands }}
+ WorkItemDirectory: ${{ parameters.WorkItemDirectory }}
+ WorkItemCommand: ${{ parameters.WorkItemCommand }}
+ WorkItemTimeout: ${{ parameters.WorkItemTimeout }}
+ CorrelationPayloadDirectory: ${{ parameters.CorrelationPayloadDirectory }}
+ XUnitProjects: ${{ parameters.XUnitProjects }}
+ XUnitWorkItemTimeout: ${{ parameters.XUnitWorkItemTimeout }}
+ XUnitPublishTargetFramework: ${{ parameters.XUnitPublishTargetFramework }}
+ XUnitRuntimeTargetFramework: ${{ parameters.XUnitRuntimeTargetFramework }}
+ XUnitRunnerVersion: ${{ parameters.XUnitRunnerVersion }}
+ IncludeDotNetCli: ${{ parameters.IncludeDotNetCli }}
+ DotNetCliPackageType: ${{ parameters.DotNetCliPackageType }}
+ DotNetCliVersion: ${{ parameters.DotNetCliVersion }}
+ EnableXUnitReporter: ${{ parameters.EnableXUnitReporter }}
+ WaitForWorkItemCompletion: ${{ parameters.WaitForWorkItemCompletion }}
+ HelixBaseUri: ${{ parameters.HelixBaseUri }}
+ Creator: ${{ parameters.Creator }}
+ SYSTEM_ACCESSTOKEN: $(System.AccessToken)
+ condition: and(${{ parameters.condition }}, ne(variables['Agent.Os'], 'Windows_NT'))
+ continueOnError: ${{ parameters.continueOnError }}
diff --git a/eng/common/templates/steps/source-build.yml b/eng/common/templates/steps/source-build.yml
new file mode 100644
index 000000000..e20637ed6
--- /dev/null
+++ b/eng/common/templates/steps/source-build.yml
@@ -0,0 +1,71 @@
+parameters:
+ # This template adds arcade-powered source-build to CI.
+
+ # This is a 'steps' template, and is intended for advanced scenarios where the existing build
+ # infra has a careful build methodology that must be followed. For example, a repo
+ # (dotnet/runtime) might choose to clone the GitHub repo only once and store it as a pipeline
+ # artifact for all subsequent jobs to use, to reduce dependence on a strong network connection to
+ # GitHub. Using this steps template leaves room for that infra to be included.
+
+ # Defines the platform on which to run the steps. See 'eng/common/templates/job/source-build.yml'
+ # for details. The entire object is described in the 'job' template for simplicity, even though
+ # the usage of the properties on this object is split between the 'job' and 'steps' templates.
+ platform: {}
+
+steps:
+# Build. Keep it self-contained for simple reusability. (No source-build-specific job variables.)
+- script: |
+ set -x
+ df -h
+
+ buildConfig=Release
+ # Check if AzDO substitutes in a build config from a variable, and use it if so.
+ if [ '$(_BuildConfig)' != '$''(_BuildConfig)' ]; then
+ buildConfig='$(_BuildConfig)'
+ fi
+
+ officialBuildArgs=
+ if [ '${{ and(ne(variables['System.TeamProject'], 'public'), notin(variables['Build.Reason'], 'PullRequest')) }}' = 'True' ]; then
+ officialBuildArgs='/p:DotNetPublishUsingPipelines=true /p:OfficialBuildId=$(BUILD.BUILDNUMBER)'
+ fi
+
+ targetRidArgs=
+ if [ '${{ parameters.platform.targetRID }}' != '' ]; then
+ targetRidArgs='/p:TargetRid=${{ parameters.platform.targetRID }}'
+ fi
+
+ publishArgs=
+ if [ '${{ parameters.platform.skipPublishValidation }}' != 'true' ]; then
+ publishArgs='--publish'
+ fi
+
+ ${{ coalesce(parameters.platform.buildScript, './build.sh') }} --ci \
+ --configuration $buildConfig \
+ --restore --build --pack $publishArgs -bl \
+ $officialBuildArgs \
+ $targetRidArgs \
+ /p:SourceBuildNonPortable=${{ parameters.platform.nonPortable }} \
+ /p:ArcadeBuildFromSource=true
+ displayName: Build
+
+# Upload build logs for diagnosis.
+- task: CopyFiles@2
+ displayName: Prepare BuildLogs staging directory
+ inputs:
+ SourceFolder: '$(Build.SourcesDirectory)'
+ Contents: |
+ **/*.log
+ **/*.binlog
+ artifacts/source-build/self/prebuilt-report/**
+ TargetFolder: '$(Build.StagingDirectory)/BuildLogs'
+ CleanTargetFolder: true
+ continueOnError: true
+ condition: succeededOrFailed()
+
+- task: PublishPipelineArtifact@1
+ displayName: Publish BuildLogs
+ inputs:
+ targetPath: '$(Build.StagingDirectory)/BuildLogs'
+ artifactName: BuildLogs_SourceBuild_${{ parameters.platform.name }}_Attempt$(System.JobAttempt)
+ continueOnError: true
+ condition: succeededOrFailed()
diff --git a/eng/common/templates/steps/telemetry-end.yml b/eng/common/templates/steps/telemetry-end.yml
new file mode 100644
index 000000000..fadc04ca1
--- /dev/null
+++ b/eng/common/templates/steps/telemetry-end.yml
@@ -0,0 +1,102 @@
+parameters:
+ maxRetries: 5
+ retryDelay: 10 # in seconds
+
+steps:
+- bash: |
+ if [ "$AGENT_JOBSTATUS" = "Succeeded" ] || [ "$AGENT_JOBSTATUS" = "PartiallySucceeded" ]; then
+ errorCount=0
+ else
+ errorCount=1
+ fi
+ warningCount=0
+
+ curlStatus=1
+ retryCount=0
+ # retry loop to harden against spotty telemetry connections
+ # we don't retry successes and 4xx client errors
+ until [[ $curlStatus -eq 0 || ( $curlStatus -ge 400 && $curlStatus -le 499 ) || $retryCount -ge $MaxRetries ]]
+ do
+ if [ $retryCount -gt 0 ]; then
+ echo "Failed to send telemetry to Helix; waiting $RetryDelay seconds before retrying..."
+ sleep $RetryDelay
+ fi
+
+ # create a temporary file for curl output
+ res=`mktemp`
+
+ curlResult=`
+ curl --verbose --output $res --write-out "%{http_code}"\
+ -H 'Content-Type: application/json' \
+ -H "X-Helix-Job-Token: $Helix_JobToken" \
+ -H 'Content-Length: 0' \
+ -X POST -G "https://helix.dot.net/api/2018-03-14/telemetry/job/build/$Helix_WorkItemId/finish" \
+ --data-urlencode "errorCount=$errorCount" \
+ --data-urlencode "warningCount=$warningCount"`
+ curlStatus=$?
+
+ if [ $curlStatus -eq 0 ]; then
+ if [ $curlResult -gt 299 ] || [ $curlResult -lt 200 ]; then
+ curlStatus=$curlResult
+ fi
+ fi
+
+ let retryCount++
+ done
+
+ if [ $curlStatus -ne 0 ]; then
+ echo "Failed to Send Build Finish information after $retryCount retries"
+ vstsLogOutput="vso[task.logissue type=error;sourcepath=templates/steps/telemetry-end.yml;code=1;]Failed to Send Build Finish information: $curlStatus"
+ echo "##$vstsLogOutput"
+ exit 1
+ fi
+ displayName: Send Unix Build End Telemetry
+ env:
+ # defined via VSTS variables in start-job.sh
+ Helix_JobToken: $(Helix_JobToken)
+ Helix_WorkItemId: $(Helix_WorkItemId)
+ MaxRetries: ${{ parameters.maxRetries }}
+ RetryDelay: ${{ parameters.retryDelay }}
+ condition: and(always(), ne(variables['Agent.Os'], 'Windows_NT'))
+- powershell: |
+ if (($env:Agent_JobStatus -eq 'Succeeded') -or ($env:Agent_JobStatus -eq 'PartiallySucceeded')) {
+ $ErrorCount = 0
+ } else {
+ $ErrorCount = 1
+ }
+ $WarningCount = 0
+
+ # Basic retry loop to harden against server flakiness
+ $retryCount = 0
+ while ($retryCount -lt $env:MaxRetries) {
+ try {
+ Invoke-RestMethod -Uri "https://helix.dot.net/api/2018-03-14/telemetry/job/build/$env:Helix_WorkItemId/finish?errorCount=$ErrorCount&warningCount=$WarningCount" -Method Post -ContentType "application/json" -Body "" `
+ -Headers @{ 'X-Helix-Job-Token'=$env:Helix_JobToken }
+ break
+ }
+ catch {
+ $statusCode = $_.Exception.Response.StatusCode.value__
+ if ($statusCode -ge 400 -and $statusCode -le 499) {
+ Write-Host "##vso[task.logissue]error Failed to send telemetry to Helix (status code $statusCode); not retrying (4xx client error)"
+ Write-Host "##vso[task.logissue]error ", $_.Exception.GetType().FullName, $_.Exception.Message
+ exit 1
+ }
+ Write-Host "Failed to send telemetry to Helix (status code $statusCode); waiting $env:RetryDelay seconds before retrying..."
+ $retryCount++
+ sleep $env:RetryDelay
+ continue
+ }
+ }
+
+ if ($retryCount -ge $env:MaxRetries) {
+ Write-Host "##vso[task.logissue]error Failed to send telemetry to Helix after $retryCount retries."
+ exit 1
+ }
+ displayName: Send Windows Build End Telemetry
+ env:
+ # defined via VSTS variables in start-job.ps1
+ Helix_JobToken: $(Helix_JobToken)
+ Helix_WorkItemId: $(Helix_WorkItemId)
+ MaxRetries: ${{ parameters.maxRetries }}
+ RetryDelay: ${{ parameters.retryDelay }}
+ condition: and(always(),eq(variables['Agent.Os'], 'Windows_NT'))
diff --git a/eng/common/templates/steps/telemetry-start.yml b/eng/common/templates/steps/telemetry-start.yml
new file mode 100644
index 000000000..32c01ef0b
--- /dev/null
+++ b/eng/common/templates/steps/telemetry-start.yml
@@ -0,0 +1,241 @@
+parameters:
+ helixSource: 'undefined_defaulted_in_telemetry.yml'
+ helixType: 'undefined_defaulted_in_telemetry.yml'
+ buildConfig: ''
+ runAsPublic: false
+ maxRetries: 5
+ retryDelay: 10 # in seconds
+
+steps:
+- ${{ if and(eq(parameters.runAsPublic, 'false'), not(eq(variables['System.TeamProject'], 'public'))) }}:
+ - task: AzureKeyVault@1
+ inputs:
+ azureSubscription: 'HelixProd_KeyVault'
+ KeyVaultName: HelixProdKV
+ SecretsFilter: 'HelixApiAccessToken'
+ condition: always()
+- bash: |
+ # create a temporary file
+ jobInfo=`mktemp`
+
+ # write job info content to temporary file
+ cat > $jobInfo < powershell invocations
+# as dot sourcing isn't possible.
+function InitializeDotNetCli([bool]$install, [bool]$createSdkLocationFile) {
+ if (Test-Path variable:global:_DotNetInstallDir) {
+ return $global:_DotNetInstallDir
+ }
+
+ # Don't resolve runtime, shared framework, or SDK from other locations to ensure build determinism
+ $env:DOTNET_MULTILEVEL_LOOKUP=0
+
+ # Disable first run since we do not need all ASP.NET packages restored.
+ $env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
+
+ # Disable telemetry on CI.
+ if ($ci) {
+ $env:DOTNET_CLI_TELEMETRY_OPTOUT=1
+ }
+
+ # Source Build uses DotNetCoreSdkDir variable
+ if ($env:DotNetCoreSdkDir -ne $null) {
+ $env:DOTNET_INSTALL_DIR = $env:DotNetCoreSdkDir
+ }
+
+ # Find the first path on %PATH% that contains the dotnet.exe
+ if ($useInstalledDotNetCli -and (-not $globalJsonHasRuntimes) -and ($env:DOTNET_INSTALL_DIR -eq $null)) {
+ $dotnetExecutable = GetExecutableFileName 'dotnet'
+ $dotnetCmd = Get-Command $dotnetExecutable -ErrorAction SilentlyContinue
+
+ if ($dotnetCmd -ne $null) {
+ $env:DOTNET_INSTALL_DIR = Split-Path $dotnetCmd.Path -Parent
+ }
+ }
+
+ $dotnetSdkVersion = $GlobalJson.tools.dotnet
+
+ # Use dotnet installation specified in DOTNET_INSTALL_DIR if it contains the required SDK version,
+ # otherwise install the dotnet CLI and SDK to repo local .dotnet directory to avoid potential permission issues.
+ if ((-not $globalJsonHasRuntimes) -and (-not [string]::IsNullOrEmpty($env:DOTNET_INSTALL_DIR)) -and (Test-Path(Join-Path $env:DOTNET_INSTALL_DIR "sdk\$dotnetSdkVersion"))) {
+ $dotnetRoot = $env:DOTNET_INSTALL_DIR
+ } else {
+ $dotnetRoot = Join-Path $RepoRoot '.dotnet'
+
+ if (-not (Test-Path(Join-Path $dotnetRoot "sdk\$dotnetSdkVersion"))) {
+ if ($install) {
+ InstallDotNetSdk $dotnetRoot $dotnetSdkVersion
+ } else {
+ Write-PipelineTelemetryError -Category 'InitializeToolset' -Message "Unable to find dotnet with SDK version '$dotnetSdkVersion'"
+ ExitWithExitCode 1
+ }
+ }
+
+ $env:DOTNET_INSTALL_DIR = $dotnetRoot
+ }
+
+ # Creates a temporary file under the toolset dir.
+ # The following code block is protecting against concurrent access so that this function can
+ # be called in parallel.
+ if ($createSdkLocationFile) {
+ do {
+ $sdkCacheFileTemp = Join-Path $ToolsetDir $([System.IO.Path]::GetRandomFileName())
+ }
+ until (!(Test-Path $sdkCacheFileTemp))
+ Set-Content -Path $sdkCacheFileTemp -Value $dotnetRoot
+
+ try {
+ Move-Item -Force $sdkCacheFileTemp (Join-Path $ToolsetDir 'sdk.txt')
+ } catch {
+ # Somebody beat us
+ Remove-Item -Path $sdkCacheFileTemp
+ }
+ }
+
+ # Add dotnet to PATH. This prevents any bare invocation of dotnet in custom
+ # build steps from using anything other than what we've downloaded.
+ # It also ensures that VS msbuild will use the downloaded sdk targets.
+ $env:PATH = "$dotnetRoot;$env:PATH"
+
+ # Make Sure that our bootstrapped dotnet cli is available in future steps of the Azure Pipelines build
+ Write-PipelinePrependPath -Path $dotnetRoot
+
+ Write-PipelineSetVariable -Name 'DOTNET_MULTILEVEL_LOOKUP' -Value '0'
+ Write-PipelineSetVariable -Name 'DOTNET_SKIP_FIRST_TIME_EXPERIENCE' -Value '1'
+
+ return $global:_DotNetInstallDir = $dotnetRoot
+}
+
+function Retry($downloadBlock, $maxRetries = 5) {
+ $retries = 1
+
+ while($true) {
+ try {
+ & $downloadBlock
+ break
+ }
+ catch {
+ Write-PipelineTelemetryError -Category 'InitializeToolset' -Message $_
+ }
+
+ if (++$retries -le $maxRetries) {
+ $delayInSeconds = [math]::Pow(2, $retries) - 1 # Exponential backoff
+ Write-Host "Retrying. Waiting for $delayInSeconds seconds before next attempt ($retries of $maxRetries)."
+ Start-Sleep -Seconds $delayInSeconds
+ }
+ else {
+ Write-PipelineTelemetryError -Category 'InitializeToolset' -Message "Unable to download file in $maxRetries attempts."
+ break
+ }
+
+ }
+}
+
+function GetDotNetInstallScript([string] $dotnetRoot) {
+ $installScript = Join-Path $dotnetRoot 'dotnet-install.ps1'
+ if (!(Test-Path $installScript)) {
+ Create-Directory $dotnetRoot
+ $ProgressPreference = 'SilentlyContinue' # Don't display the console progress UI - it's a huge perf hit
+ $uri = "https://dotnet.microsoft.com/download/dotnet/scripts/$dotnetInstallScriptVersion/dotnet-install.ps1"
+
+ Retry({
+ Write-Host "GET $uri"
+ Invoke-WebRequest $uri -OutFile $installScript
+ })
+ }
+
+ return $installScript
+}
+
+function InstallDotNetSdk([string] $dotnetRoot, [string] $version, [string] $architecture = '', [switch] $noPath) {
+ InstallDotNet $dotnetRoot $version $architecture '' $false $runtimeSourceFeed $runtimeSourceFeedKey -noPath:$noPath
+}
+
+function InstallDotNet([string] $dotnetRoot,
+ [string] $version,
+ [string] $architecture = '',
+ [string] $runtime = '',
+ [bool] $skipNonVersionedFiles = $false,
+ [string] $runtimeSourceFeed = '',
+ [string] $runtimeSourceFeedKey = '',
+ [switch] $noPath) {
+
+ $installScript = GetDotNetInstallScript $dotnetRoot
+ $installParameters = @{
+ Version = $version
+ InstallDir = $dotnetRoot
+ }
+
+ if ($architecture) { $installParameters.Architecture = $architecture }
+ if ($runtime) { $installParameters.Runtime = $runtime }
+ if ($skipNonVersionedFiles) { $installParameters.SkipNonVersionedFiles = $skipNonVersionedFiles }
+ if ($noPath) { $installParameters.NoPath = $True }
+
+ try {
+ & $installScript @installParameters
+ }
+ catch {
+ if ($runtimeSourceFeed -or $runtimeSourceFeedKey) {
+ Write-Host "Failed to install dotnet from public location. Trying from '$runtimeSourceFeed'"
+ if ($runtimeSourceFeed) { $installParameters.AzureFeed = $runtimeSourceFeed }
+
+ if ($runtimeSourceFeedKey) {
+ $decodedBytes = [System.Convert]::FromBase64String($runtimeSourceFeedKey)
+ $decodedString = [System.Text.Encoding]::UTF8.GetString($decodedBytes)
+ $installParameters.FeedCredential = $decodedString
+ }
+
+ try {
+ & $installScript @installParameters
+ }
+ catch {
+ Write-PipelineTelemetryError -Category 'InitializeToolset' -Message "Failed to install dotnet from custom location '$runtimeSourceFeed'."
+ ExitWithExitCode 1
+ }
+ } else {
+ Write-PipelineTelemetryError -Category 'InitializeToolset' -Message "Failed to install dotnet from public location."
+ ExitWithExitCode 1
+ }
+ }
+}
+
+#
+# Locates Visual Studio MSBuild installation.
+# The preference order for MSBuild to use is as follows:
+#
+# 1. MSBuild from an active VS command prompt
+# 2. MSBuild from a compatible VS installation
+# 3. MSBuild from the xcopy tool package
+#
+# Returns full path to msbuild.exe.
+# Throws on failure.
+#
+function InitializeVisualStudioMSBuild([bool]$install, [object]$vsRequirements = $null) {
+ if (-not (IsWindowsPlatform)) {
+ throw "Cannot initialize Visual Studio on non-Windows"
+ }
+
+ if (Test-Path variable:global:_MSBuildExe) {
+ return $global:_MSBuildExe
+ }
+
+ # Minimum VS version to require.
+ $vsMinVersionReqdStr = '16.8'
+ $vsMinVersionReqd = [Version]::new($vsMinVersionReqdStr)
+
+ # If the version of msbuild is going to be xcopied,
+ # use this version. Version matches a package here:
+ # https://dev.azure.com/dnceng/public/_packaging?_a=package&feed=dotnet-eng&package=RoslynTools.MSBuild&protocolType=NuGet&version=16.10.0-preview2&view=overview
+ $defaultXCopyMSBuildVersion = '16.10.0-preview2'
+
+ if (!$vsRequirements) { $vsRequirements = $GlobalJson.tools.vs }
+ $vsMinVersionStr = if ($vsRequirements.version) { $vsRequirements.version } else { $vsMinVersionReqdStr }
+ $vsMinVersion = [Version]::new($vsMinVersionStr)
+
+ # Try msbuild command available in the environment.
+ if ($env:VSINSTALLDIR -ne $null) {
+ $msbuildCmd = Get-Command 'msbuild.exe' -ErrorAction SilentlyContinue
+ if ($msbuildCmd -ne $null) {
+ # Workaround for https://github.com/dotnet/roslyn/issues/35793
+ # Due to this issue $msbuildCmd.Version returns 0.0.0.0 for msbuild.exe 16.2+
+ $msbuildVersion = [Version]::new((Get-Item $msbuildCmd.Path).VersionInfo.ProductVersion.Split([char[]]@('-', '+'))[0])
+
+ if ($msbuildVersion -ge $vsMinVersion) {
+ return $global:_MSBuildExe = $msbuildCmd.Path
+ }
+
+ # Report error - the developer environment is initialized with incompatible VS version.
+ throw "Developer Command Prompt for VS $($env:VisualStudioVersion) is not recent enough. Please upgrade to $vsMinVersionStr or build from a plain CMD window"
+ }
+ }
+
+ # Locate Visual Studio installation or download x-copy msbuild.
+ $vsInfo = LocateVisualStudio $vsRequirements
+ if ($vsInfo -ne $null) {
+ $vsInstallDir = $vsInfo.installationPath
+ $vsMajorVersion = $vsInfo.installationVersion.Split('.')[0]
+
+ InitializeVisualStudioEnvironmentVariables $vsInstallDir $vsMajorVersion
+ } else {
+
+ if (Get-Member -InputObject $GlobalJson.tools -Name 'xcopy-msbuild') {
+ $xcopyMSBuildVersion = $GlobalJson.tools.'xcopy-msbuild'
+ $vsMajorVersion = $xcopyMSBuildVersion.Split('.')[0]
+ } else {
+ #if vs version provided in global.json is incompatible (too low) then use the default version for xcopy msbuild download
+ if($vsMinVersion -lt $vsMinVersionReqd){
+ Write-Host "Using xcopy-msbuild version of $defaultXCopyMSBuildVersion since VS version $vsMinVersionStr provided in global.json is not compatible"
+ $xcopyMSBuildVersion = $defaultXCopyMSBuildVersion
+ }
+ else{
+ # If the VS version IS compatible, look for an xcopy msbuild package
+ # with a version matching VS.
+ # Note: If this version does not exist, then an explicit version of xcopy msbuild
+ # can be specified in global.json. This will be required for pre-release versions of msbuild.
+ $vsMajorVersion = $vsMinVersion.Major
+ $vsMinorVersion = $vsMinVersion.Minor
+ $xcopyMSBuildVersion = "$vsMajorVersion.$vsMinorVersion.0"
+ }
+ }
+
+ $vsInstallDir = $null
+ if ($xcopyMSBuildVersion.Trim() -ine "none") {
+ $vsInstallDir = InitializeXCopyMSBuild $xcopyMSBuildVersion $install
+ if ($vsInstallDir -eq $null) {
+ throw "Could not xcopy msbuild. Please check that package 'RoslynTools.MSBuild @ $xcopyMSBuildVersion' exists on feed 'dotnet-eng'."
+ }
+ }
+ if ($vsInstallDir -eq $null) {
+ throw 'Unable to find Visual Studio that has required version and components installed'
+ }
+ }
+
+ $msbuildVersionDir = if ([int]$vsMajorVersion -lt 16) { "$vsMajorVersion.0" } else { "Current" }
+
+ $local:BinFolder = Join-Path $vsInstallDir "MSBuild\$msbuildVersionDir\Bin"
+ $local:Prefer64bit = if (Get-Member -InputObject $vsRequirements -Name 'Prefer64bit') { $vsRequirements.Prefer64bit } else { $false }
+ if ($local:Prefer64bit -and (Test-Path(Join-Path $local:BinFolder "amd64"))) {
+ $global:_MSBuildExe = Join-Path $local:BinFolder "amd64\msbuild.exe"
+ } else {
+ $global:_MSBuildExe = Join-Path $local:BinFolder "msbuild.exe"
+ }
+
+ return $global:_MSBuildExe
+}
+
+function InitializeVisualStudioEnvironmentVariables([string] $vsInstallDir, [string] $vsMajorVersion) {
+ $env:VSINSTALLDIR = $vsInstallDir
+ Set-Item "env:VS$($vsMajorVersion)0COMNTOOLS" (Join-Path $vsInstallDir "Common7\Tools\")
+
+ $vsSdkInstallDir = Join-Path $vsInstallDir "VSSDK\"
+ if (Test-Path $vsSdkInstallDir) {
+ Set-Item "env:VSSDK$($vsMajorVersion)0Install" $vsSdkInstallDir
+ $env:VSSDKInstall = $vsSdkInstallDir
+ }
+}
+
+function InstallXCopyMSBuild([string]$packageVersion) {
+ return InitializeXCopyMSBuild $packageVersion -install $true
+}
+
+function InitializeXCopyMSBuild([string]$packageVersion, [bool]$install) {
+ $packageName = 'RoslynTools.MSBuild'
+ $packageDir = Join-Path $ToolsDir "msbuild\$packageVersion"
+ $packagePath = Join-Path $packageDir "$packageName.$packageVersion.nupkg"
+
+ if (!(Test-Path $packageDir)) {
+ if (!$install) {
+ return $null
+ }
+
+ Create-Directory $packageDir
+
+ Write-Host "Downloading $packageName $packageVersion"
+ $ProgressPreference = 'SilentlyContinue' # Don't display the console progress UI - it's a huge perf hit
+ Retry({
+ Invoke-WebRequest "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/flat2/$packageName/$packageVersion/$packageName.$packageVersion.nupkg" -OutFile $packagePath
+ })
+
+ Unzip $packagePath $packageDir
+ }
+
+ return Join-Path $packageDir 'tools'
+}
+
+#
+# Locates Visual Studio instance that meets the minimal requirements specified by tools.vs object in global.json.
+#
+# The following properties of tools.vs are recognized:
+# "version": "{major}.{minor}"
+# Two part minimal VS version, e.g. "15.9", "16.0", etc.
+# "components": ["componentId1", "componentId2", ...]
+# Array of ids of workload components that must be available in the VS instance.
+# See e.g. https://docs.microsoft.com/en-us/visualstudio/install/workload-component-id-vs-enterprise?view=vs-2017
+#
+# Returns JSON describing the located VS instance (same format as returned by vswhere),
+# or $null if no instance meeting the requirements is found on the machine.
+#
+function LocateVisualStudio([object]$vsRequirements = $null){
+ if (-not (IsWindowsPlatform)) {
+ throw "Cannot run vswhere on non-Windows platforms."
+ }
+
+ if (Get-Member -InputObject $GlobalJson.tools -Name 'vswhere') {
+ $vswhereVersion = $GlobalJson.tools.vswhere
+ } else {
+ $vswhereVersion = '2.5.2'
+ }
+
+ $vsWhereDir = Join-Path $ToolsDir "vswhere\$vswhereVersion"
+ $vsWhereExe = Join-Path $vsWhereDir 'vswhere.exe'
+
+ if (!(Test-Path $vsWhereExe)) {
+ Create-Directory $vsWhereDir
+ Write-Host 'Downloading vswhere'
+ Retry({
+ Invoke-WebRequest "https://netcorenativeassets.blob.core.windows.net/resource-packages/external/windows/vswhere/$vswhereVersion/vswhere.exe" -OutFile $vswhereExe
+ })
+ }
+
+ if (!$vsRequirements) { $vsRequirements = $GlobalJson.tools.vs }
+ $args = @('-latest', '-format', 'json', '-requires', 'Microsoft.Component.MSBuild', '-products', '*')
+
+ if (!$excludePrereleaseVS) {
+ $args += '-prerelease'
+ }
+
+ if (Get-Member -InputObject $vsRequirements -Name 'version') {
+ $args += '-version'
+ $args += $vsRequirements.version
+ }
+
+ if (Get-Member -InputObject $vsRequirements -Name 'components') {
+ foreach ($component in $vsRequirements.components) {
+ $args += '-requires'
+ $args += $component
+ }
+ }
+
+ $vsInfo =& $vsWhereExe $args | ConvertFrom-Json
+
+ if ($lastExitCode -ne 0) {
+ return $null
+ }
+
+ # use first matching instance
+ return $vsInfo[0]
+}
+
+function InitializeBuildTool() {
+ if (Test-Path variable:global:_BuildTool) {
+ # If the requested msbuild parameters do not match, clear the cached variables.
+ if($global:_BuildTool.Contains('ExcludePrereleaseVS') -and $global:_BuildTool.ExcludePrereleaseVS -ne $excludePrereleaseVS) {
+ Remove-Item variable:global:_BuildTool
+ Remove-Item variable:global:_MSBuildExe
+ } else {
+ return $global:_BuildTool
+ }
+ }
+
+ if (-not $msbuildEngine) {
+ $msbuildEngine = GetDefaultMSBuildEngine
+ }
+
+ # Initialize dotnet cli if listed in 'tools'
+ $dotnetRoot = $null
+ if (Get-Member -InputObject $GlobalJson.tools -Name 'dotnet') {
+ $dotnetRoot = InitializeDotNetCli -install:$restore
+ }
+
+ if ($msbuildEngine -eq 'dotnet') {
+ if (!$dotnetRoot) {
+ Write-PipelineTelemetryError -Category 'InitializeToolset' -Message "/global.json must specify 'tools.dotnet'."
+ ExitWithExitCode 1
+ }
+ $dotnetPath = Join-Path $dotnetRoot (GetExecutableFileName 'dotnet')
+ $buildTool = @{ Path = $dotnetPath; Command = 'msbuild'; Tool = 'dotnet'; Framework = 'netcoreapp3.1' }
+ } elseif ($msbuildEngine -eq "vs") {
+ try {
+ $msbuildPath = InitializeVisualStudioMSBuild -install:$restore
+ } catch {
+ Write-PipelineTelemetryError -Category 'InitializeToolset' -Message $_
+ ExitWithExitCode 1
+ }
+
+ $buildTool = @{ Path = $msbuildPath; Command = ""; Tool = "vs"; Framework = "net472"; ExcludePrereleaseVS = $excludePrereleaseVS }
+ } else {
+ Write-PipelineTelemetryError -Category 'InitializeToolset' -Message "Unexpected value of -msbuildEngine: '$msbuildEngine'."
+ ExitWithExitCode 1
+ }
+
+ return $global:_BuildTool = $buildTool
+}
+
+function GetDefaultMSBuildEngine() {
+ # Presence of tools.vs indicates the repo needs to build using VS msbuild on Windows.
+ if (Get-Member -InputObject $GlobalJson.tools -Name 'vs') {
+ return 'vs'
+ }
+
+ if (Get-Member -InputObject $GlobalJson.tools -Name 'dotnet') {
+ return 'dotnet'
+ }
+
+ Write-PipelineTelemetryError -Category 'InitializeToolset' -Message "-msbuildEngine must be specified, or /global.json must specify 'tools.dotnet' or 'tools.vs'."
+ ExitWithExitCode 1
+}
+
+function GetNuGetPackageCachePath() {
+ if ($env:NUGET_PACKAGES -eq $null) {
+ # Use local cache on CI to ensure deterministic build.
+ # Avoid using the http cache as workaround for https://github.com/NuGet/Home/issues/3116
+ # use global cache in dev builds to avoid cost of downloading packages.
+ # For directory normalization, see also: https://github.com/NuGet/Home/issues/7968
+ if ($useGlobalNuGetCache) {
+ $env:NUGET_PACKAGES = Join-Path $env:UserProfile '.nuget\packages\'
+ } else {
+ $env:NUGET_PACKAGES = Join-Path $RepoRoot '.packages\'
+ $env:RESTORENOCACHE = $true
+ }
+ }
+
+ return $env:NUGET_PACKAGES
+}
+
+# Returns a full path to an Arcade SDK task project file.
+function GetSdkTaskProject([string]$taskName) {
+ return Join-Path (Split-Path (InitializeToolset) -Parent) "SdkTasks\$taskName.proj"
+}
+
+function InitializeNativeTools() {
+ if (-Not (Test-Path variable:DisableNativeToolsetInstalls) -And (Get-Member -InputObject $GlobalJson -Name "native-tools")) {
+ $nativeArgs= @{}
+ if ($ci) {
+ $nativeArgs = @{
+ InstallDirectory = "$ToolsDir"
+ }
+ }
+ & "$PSScriptRoot/init-tools-native.ps1" @nativeArgs
+ }
+}
+
+function InitializeToolset() {
+ if (Test-Path variable:global:_ToolsetBuildProj) {
+ return $global:_ToolsetBuildProj
+ }
+
+ $nugetCache = GetNuGetPackageCachePath
+
+ $toolsetVersion = $GlobalJson.'msbuild-sdks'.'Microsoft.DotNet.Arcade.Sdk'
+ $toolsetLocationFile = Join-Path $ToolsetDir "$toolsetVersion.txt"
+
+ if (Test-Path $toolsetLocationFile) {
+ $path = Get-Content $toolsetLocationFile -TotalCount 1
+ if (Test-Path $path) {
+ return $global:_ToolsetBuildProj = $path
+ }
+ }
+
+ if (-not $restore) {
+ Write-PipelineTelemetryError -Category 'InitializeToolset' -Message "Toolset version $toolsetVersion has not been restored."
+ ExitWithExitCode 1
+ }
+
+ $buildTool = InitializeBuildTool
+
+ $proj = Join-Path $ToolsetDir 'restore.proj'
+ $bl = if ($binaryLog) { '/bl:' + (Join-Path $LogDir 'ToolsetRestore.binlog') } else { '' }
+
+ '' | Set-Content $proj
+
+ MSBuild-Core $proj $bl /t:__WriteToolsetLocation /clp:ErrorsOnly`;NoSummary /p:__ToolsetLocationOutputFile=$toolsetLocationFile
+
+ $path = Get-Content $toolsetLocationFile -Encoding UTF8 -TotalCount 1
+ if (!(Test-Path $path)) {
+ throw "Invalid toolset path: $path"
+ }
+
+ return $global:_ToolsetBuildProj = $path
+}
+
+function ExitWithExitCode([int] $exitCode) {
+ if ($ci -and $prepareMachine) {
+ Stop-Processes
+ }
+ exit $exitCode
+}
+
+# Check if $LASTEXITCODE is a nonzero exit code (NZEC). If so, print a Azure Pipeline error for
+# diagnostics, then exit the script with the $LASTEXITCODE.
+function Exit-IfNZEC([string] $category = "General") {
+ Write-Host "Exit code $LASTEXITCODE"
+ if ($LASTEXITCODE -ne 0) {
+ $message = "Last command failed with exit code $LASTEXITCODE."
+ Write-PipelineTelemetryError -Force -Category $category -Message $message
+ ExitWithExitCode $LASTEXITCODE
+ }
+}
+
+function Stop-Processes() {
+ Write-Host 'Killing running build processes...'
+ foreach ($processName in $processesToStopOnExit) {
+ Get-Process -Name $processName -ErrorAction SilentlyContinue | Stop-Process
+ }
+}
+
+#
+# Executes msbuild (or 'dotnet msbuild') with arguments passed to the function.
+# The arguments are automatically quoted.
+# Terminates the script if the build fails.
+#
+function MSBuild() {
+ if ($pipelinesLog) {
+ $buildTool = InitializeBuildTool
+
+ if ($ci -and $buildTool.Tool -eq 'dotnet') {
+ $env:NUGET_PLUGIN_HANDSHAKE_TIMEOUT_IN_SECONDS = 20
+ $env:NUGET_PLUGIN_REQUEST_TIMEOUT_IN_SECONDS = 20
+ Write-PipelineSetVariable -Name 'NUGET_PLUGIN_HANDSHAKE_TIMEOUT_IN_SECONDS' -Value '20'
+ Write-PipelineSetVariable -Name 'NUGET_PLUGIN_REQUEST_TIMEOUT_IN_SECONDS' -Value '20'
+ }
+
+ $toolsetBuildProject = InitializeToolset
+ $basePath = Split-Path -parent $toolsetBuildProject
+ $possiblePaths = @(
+ # new scripts need to work with old packages, so we need to look for the old names/versions
+ (Join-Path $basePath (Join-Path $buildTool.Framework 'Microsoft.DotNet.ArcadeLogging.dll')),
+ (Join-Path $basePath (Join-Path $buildTool.Framework 'Microsoft.DotNet.Arcade.Sdk.dll')),
+ (Join-Path $basePath (Join-Path netcoreapp2.1 'Microsoft.DotNet.ArcadeLogging.dll')),
+ (Join-Path $basePath (Join-Path netcoreapp2.1 'Microsoft.DotNet.Arcade.Sdk.dll'))
+ )
+ $selectedPath = $null
+ foreach ($path in $possiblePaths) {
+ if (Test-Path $path -PathType Leaf) {
+ $selectedPath = $path
+ break
+ }
+ }
+ if (-not $selectedPath) {
+ Write-PipelineTelemetryError -Category 'Build' -Message 'Unable to find arcade sdk logger assembly.'
+ ExitWithExitCode 1
+ }
+ $args += "/logger:$selectedPath"
+ }
+
+ MSBuild-Core @args
+}
+
+#
+# Executes msbuild (or 'dotnet msbuild') with arguments passed to the function.
+# The arguments are automatically quoted.
+# Terminates the script if the build fails.
+#
+function MSBuild-Core() {
+ if ($ci) {
+ if (!$binaryLog -and !$excludeCIBinarylog) {
+ Write-PipelineTelemetryError -Category 'Build' -Message 'Binary log must be enabled in CI build, or explicitly opted-out from with the -excludeCIBinarylog switch.'
+ ExitWithExitCode 1
+ }
+
+ if ($nodeReuse) {
+ Write-PipelineTelemetryError -Category 'Build' -Message 'Node reuse must be disabled in CI build.'
+ ExitWithExitCode 1
+ }
+ }
+
+ $buildTool = InitializeBuildTool
+
+ $cmdArgs = "$($buildTool.Command) /m /nologo /clp:Summary /v:$verbosity /nr:$nodeReuse /p:ContinuousIntegrationBuild=$ci"
+
+ if ($warnAsError) {
+ $cmdArgs += ' /warnaserror /p:TreatWarningsAsErrors=true'
+ }
+ else {
+ $cmdArgs += ' /p:TreatWarningsAsErrors=false'
+ }
+
+ foreach ($arg in $args) {
+ if ($null -ne $arg -and $arg.Trim() -ne "") {
+ if ($arg.EndsWith('\')) {
+ $arg = $arg + "\"
+ }
+ $cmdArgs += " `"$arg`""
+ }
+ }
+
+ $env:ARCADE_BUILD_TOOL_COMMAND = "$($buildTool.Path) $cmdArgs"
+
+ $exitCode = Exec-Process $buildTool.Path $cmdArgs
+
+ if ($exitCode -ne 0) {
+ # We should not Write-PipelineTaskError here because that message shows up in the build summary
+ # The build already logged an error, that's the reason it failed. Producing an error here only adds noise.
+ Write-Host "Build failed with exit code $exitCode. Check errors above." -ForegroundColor Red
+
+ $buildLog = GetMSBuildBinaryLogCommandLineArgument $args
+ if ($null -ne $buildLog) {
+ Write-Host "See log: $buildLog" -ForegroundColor DarkGray
+ }
+
+ if ($ci) {
+ Write-PipelineSetResult -Result "Failed" -Message "msbuild execution failed."
+ # Exiting with an exit code causes the azure pipelines task to log yet another "noise" error
+ # The above Write-PipelineSetResult will cause the task to be marked as failure without adding yet another error
+ ExitWithExitCode 0
+ } else {
+ ExitWithExitCode $exitCode
+ }
+ }
+}
+
+function GetMSBuildBinaryLogCommandLineArgument($arguments) {
+ foreach ($argument in $arguments) {
+ if ($argument -ne $null) {
+ $arg = $argument.Trim()
+ if ($arg.StartsWith('/bl:', "OrdinalIgnoreCase")) {
+ return $arg.Substring('/bl:'.Length)
+ }
+
+ if ($arg.StartsWith('/binaryLogger:', 'OrdinalIgnoreCase')) {
+ return $arg.Substring('/binaryLogger:'.Length)
+ }
+ }
+ }
+
+ return $null
+}
+
+function GetExecutableFileName($baseName) {
+ if (IsWindowsPlatform) {
+ return "$baseName.exe"
+ }
+ else {
+ return $baseName
+ }
+}
+
+function IsWindowsPlatform() {
+ return [environment]::OSVersion.Platform -eq [PlatformID]::Win32NT
+}
+
+function Get-Darc($version) {
+ $darcPath = "$TempDir\darc\$(New-Guid)"
+ if ($version -ne $null) {
+ & $PSScriptRoot\darc-init.ps1 -toolpath $darcPath -darcVersion $version | Out-Host
+ } else {
+ & $PSScriptRoot\darc-init.ps1 -toolpath $darcPath | Out-Host
+ }
+ return "$darcPath\darc.exe"
+}
+
+. $PSScriptRoot\pipeline-logging-functions.ps1
+
+$RepoRoot = Resolve-Path (Join-Path $PSScriptRoot '..\..\')
+$EngRoot = Resolve-Path (Join-Path $PSScriptRoot '..')
+$ArtifactsDir = Join-Path $RepoRoot 'artifacts'
+$ToolsetDir = Join-Path $ArtifactsDir 'toolset'
+$ToolsDir = Join-Path $RepoRoot '.tools'
+$LogDir = Join-Path (Join-Path $ArtifactsDir 'log') $configuration
+$TempDir = Join-Path (Join-Path $ArtifactsDir 'tmp') $configuration
+$GlobalJson = Get-Content -Raw -Path (Join-Path $RepoRoot 'global.json') | ConvertFrom-Json
+# true if global.json contains a "runtimes" section
+$globalJsonHasRuntimes = if ($GlobalJson.tools.PSObject.Properties.Name -Match 'runtimes') { $true } else { $false }
+
+Create-Directory $ToolsetDir
+Create-Directory $TempDir
+Create-Directory $LogDir
+
+Write-PipelineSetVariable -Name 'Artifacts' -Value $ArtifactsDir
+Write-PipelineSetVariable -Name 'Artifacts.Toolset' -Value $ToolsetDir
+Write-PipelineSetVariable -Name 'Artifacts.Log' -Value $LogDir
+Write-PipelineSetVariable -Name 'TEMP' -Value $TempDir
+Write-PipelineSetVariable -Name 'TMP' -Value $TempDir
+
+# Import custom tools configuration, if present in the repo.
+# Note: Import in global scope so that the script set top-level variables without qualification.
+if (!$disableConfigureToolsetImport) {
+ $configureToolsetScript = Join-Path $EngRoot 'configure-toolset.ps1'
+ if (Test-Path $configureToolsetScript) {
+ . $configureToolsetScript
+ if ((Test-Path variable:failOnConfigureToolsetError) -And $failOnConfigureToolsetError) {
+ if ((Test-Path variable:LastExitCode) -And ($LastExitCode -ne 0)) {
+ Write-PipelineTelemetryError -Category 'Build' -Message 'configure-toolset.ps1 returned a non-zero exit code'
+ ExitWithExitCode $LastExitCode
+ }
+ }
+ }
+}
diff --git a/eng/common/tools.sh b/eng/common/tools.sh
new file mode 100644
index 000000000..828119be4
--- /dev/null
+++ b/eng/common/tools.sh
@@ -0,0 +1,535 @@
+#!/usr/bin/env bash
+
+# Initialize variables if they aren't already defined.
+
+# CI mode - set to true on CI server for PR validation build or official build.
+ci=${ci:-false}
+
+# Set to true to use the pipelines logger which will enable Azure logging output.
+# https://github.com/Microsoft/azure-pipelines-tasks/blob/master/docs/authoring/commands.md
+# This flag is meant as a temporary opt-opt for the feature while validate it across
+# our consumers. It will be deleted in the future.
+if [[ "$ci" == true ]]; then
+ pipelines_log=${pipelines_log:-true}
+else
+ pipelines_log=${pipelines_log:-false}
+fi
+
+# Build configuration. Common values include 'Debug' and 'Release', but the repository may use other names.
+configuration=${configuration:-'Debug'}
+
+# Set to true to opt out of outputting binary log while running in CI
+exclude_ci_binary_log=${exclude_ci_binary_log:-false}
+
+if [[ "$ci" == true && "$exclude_ci_binary_log" == false ]]; then
+ binary_log_default=true
+else
+ binary_log_default=false
+fi
+
+# Set to true to output binary log from msbuild. Note that emitting binary log slows down the build.
+binary_log=${binary_log:-$binary_log_default}
+
+# Turns on machine preparation/clean up code that changes the machine state (e.g. kills build processes).
+prepare_machine=${prepare_machine:-false}
+
+# True to restore toolsets and dependencies.
+restore=${restore:-true}
+
+# Adjusts msbuild verbosity level.
+verbosity=${verbosity:-'minimal'}
+
+# Set to true to reuse msbuild nodes. Recommended to not reuse on CI.
+if [[ "$ci" == true ]]; then
+ node_reuse=${node_reuse:-false}
+else
+ node_reuse=${node_reuse:-true}
+fi
+
+# Configures warning treatment in msbuild.
+warn_as_error=${warn_as_error:-true}
+
+# True to attempt using .NET Core already that meets requirements specified in global.json
+# installed on the machine instead of downloading one.
+use_installed_dotnet_cli=${use_installed_dotnet_cli:-true}
+
+# Enable repos to use a particular version of the on-line dotnet-install scripts.
+# default URL: https://dotnet.microsoft.com/download/dotnet/scripts/v1/dotnet-install.sh
+dotnetInstallScriptVersion=${dotnetInstallScriptVersion:-'v1'}
+
+# True to use global NuGet cache instead of restoring packages to repository-local directory.
+if [[ "$ci" == true ]]; then
+ use_global_nuget_cache=${use_global_nuget_cache:-false}
+else
+ use_global_nuget_cache=${use_global_nuget_cache:-true}
+fi
+
+# Used when restoring .NET SDK from alternative feeds
+runtime_source_feed=${runtime_source_feed:-''}
+runtime_source_feed_key=${runtime_source_feed_key:-''}
+
+# Resolve any symlinks in the given path.
+function ResolvePath {
+ local path=$1
+
+ while [[ -h $path ]]; do
+ local dir="$( cd -P "$( dirname "$path" )" && pwd )"
+ path="$(readlink "$path")"
+
+ # if $path was a relative symlink, we need to resolve it relative to the path where the
+ # symlink file was located
+ [[ $path != /* ]] && path="$dir/$path"
+ done
+
+ # return value
+ _ResolvePath="$path"
+}
+
+# ReadVersionFromJson [json key]
+function ReadGlobalVersion {
+ local key=$1
+
+ if command -v jq &> /dev/null; then
+ _ReadGlobalVersion="$(jq -r ".[] | select(has(\"$key\")) | .\"$key\"" "$global_json_file")"
+ elif [[ "$(cat "$global_json_file")" =~ \"$key\"[[:space:]\:]*\"([^\"]+) ]]; then
+ _ReadGlobalVersion=${BASH_REMATCH[1]}
+ fi
+
+ if [[ -z "$_ReadGlobalVersion" ]]; then
+ Write-PipelineTelemetryError -category 'Build' "Error: Cannot find \"$key\" in $global_json_file"
+ ExitWithExitCode 1
+ fi
+}
+
+function InitializeDotNetCli {
+ if [[ -n "${_InitializeDotNetCli:-}" ]]; then
+ return
+ fi
+
+ local install=$1
+
+ # Don't resolve runtime, shared framework, or SDK from other locations to ensure build determinism
+ export DOTNET_MULTILEVEL_LOOKUP=0
+
+ # Disable first run since we want to control all package sources
+ export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
+
+ # Disable telemetry on CI
+ if [[ $ci == true ]]; then
+ export DOTNET_CLI_TELEMETRY_OPTOUT=1
+ fi
+
+ # LTTNG is the logging infrastructure used by Core CLR. Need this variable set
+ # so it doesn't output warnings to the console.
+ export LTTNG_HOME="$HOME"
+
+ # Source Build uses DotNetCoreSdkDir variable
+ if [[ -n "${DotNetCoreSdkDir:-}" ]]; then
+ export DOTNET_INSTALL_DIR="$DotNetCoreSdkDir"
+ fi
+
+ # Find the first path on $PATH that contains the dotnet.exe
+ if [[ "$use_installed_dotnet_cli" == true && $global_json_has_runtimes == false && -z "${DOTNET_INSTALL_DIR:-}" ]]; then
+ local dotnet_path=`command -v dotnet`
+ if [[ -n "$dotnet_path" ]]; then
+ ResolvePath "$dotnet_path"
+ export DOTNET_INSTALL_DIR=`dirname "$_ResolvePath"`
+ fi
+ fi
+
+ ReadGlobalVersion "dotnet"
+ local dotnet_sdk_version=$_ReadGlobalVersion
+ local dotnet_root=""
+
+ # Use dotnet installation specified in DOTNET_INSTALL_DIR if it contains the required SDK version,
+ # otherwise install the dotnet CLI and SDK to repo local .dotnet directory to avoid potential permission issues.
+ if [[ $global_json_has_runtimes == false && -n "${DOTNET_INSTALL_DIR:-}" && -d "$DOTNET_INSTALL_DIR/sdk/$dotnet_sdk_version" ]]; then
+ dotnet_root="$DOTNET_INSTALL_DIR"
+ else
+ dotnet_root="$repo_root/.dotnet"
+
+ export DOTNET_INSTALL_DIR="$dotnet_root"
+
+ if [[ ! -d "$DOTNET_INSTALL_DIR/sdk/$dotnet_sdk_version" ]]; then
+ if [[ "$install" == true ]]; then
+ InstallDotNetSdk "$dotnet_root" "$dotnet_sdk_version"
+ else
+ Write-PipelineTelemetryError -category 'InitializeToolset' "Unable to find dotnet with SDK version '$dotnet_sdk_version'"
+ ExitWithExitCode 1
+ fi
+ fi
+ fi
+
+ # Add dotnet to PATH. This prevents any bare invocation of dotnet in custom
+ # build steps from using anything other than what we've downloaded.
+ Write-PipelinePrependPath -path "$dotnet_root"
+
+ Write-PipelineSetVariable -name "DOTNET_MULTILEVEL_LOOKUP" -value "0"
+ Write-PipelineSetVariable -name "DOTNET_SKIP_FIRST_TIME_EXPERIENCE" -value "1"
+
+ # return value
+ _InitializeDotNetCli="$dotnet_root"
+}
+
+function InstallDotNetSdk {
+ local root=$1
+ local version=$2
+ local architecture="unset"
+ if [[ $# -ge 3 ]]; then
+ architecture=$3
+ fi
+ InstallDotNet "$root" "$version" $architecture 'sdk' 'false' $runtime_source_feed $runtime_source_feed_key
+}
+
+function InstallDotNet {
+ local root=$1
+ local version=$2
+
+ GetDotNetInstallScript "$root"
+ local install_script=$_GetDotNetInstallScript
+
+ local archArg=''
+ if [[ -n "${3:-}" ]] && [ "$3" != 'unset' ]; then
+ archArg="--architecture $3"
+ fi
+ local runtimeArg=''
+ if [[ -n "${4:-}" ]] && [ "$4" != 'sdk' ]; then
+ runtimeArg="--runtime $4"
+ fi
+ local skipNonVersionedFilesArg=""
+ if [[ "$#" -ge "5" ]] && [[ "$5" != 'false' ]]; then
+ skipNonVersionedFilesArg="--skip-non-versioned-files"
+ fi
+ bash "$install_script" --version $version --install-dir "$root" $archArg $runtimeArg $skipNonVersionedFilesArg || {
+ local exit_code=$?
+ echo "Failed to install dotnet SDK from public location (exit code '$exit_code')."
+
+ local runtimeSourceFeed=''
+ if [[ -n "${6:-}" ]]; then
+ runtimeSourceFeed="--azure-feed $6"
+ fi
+
+ local runtimeSourceFeedKey=''
+ if [[ -n "${7:-}" ]]; then
+ # The 'base64' binary on alpine uses '-d' and doesn't support '--decode'
+ # '-d'. To work around this, do a simple detection and switch the parameter
+ # accordingly.
+ decodeArg="--decode"
+ if base64 --help 2>&1 | grep -q "BusyBox"; then
+ decodeArg="-d"
+ fi
+ decodedFeedKey=`echo $7 | base64 $decodeArg`
+ runtimeSourceFeedKey="--feed-credential $decodedFeedKey"
+ fi
+
+ if [[ -n "$runtimeSourceFeed" || -n "$runtimeSourceFeedKey" ]]; then
+ bash "$install_script" --version $version --install-dir "$root" $archArg $runtimeArg $skipNonVersionedFilesArg $runtimeSourceFeed $runtimeSourceFeedKey || {
+ local exit_code=$?
+ Write-PipelineTelemetryError -category 'InitializeToolset' "Failed to install dotnet SDK from custom location '$runtimeSourceFeed' (exit code '$exit_code')."
+ ExitWithExitCode $exit_code
+ }
+ else
+ if [[ $exit_code != 0 ]]; then
+ Write-PipelineTelemetryError -category 'InitializeToolset' "Failed to install dotnet SDK from public location (exit code '$exit_code')."
+ fi
+ ExitWithExitCode $exit_code
+ fi
+ }
+}
+
+function with_retries {
+ local maxRetries=5
+ local retries=1
+ echo "Trying to run '$@' for maximum of $maxRetries attempts."
+ while [[ $((retries++)) -le $maxRetries ]]; do
+ "$@"
+
+ if [[ $? == 0 ]]; then
+ echo "Ran '$@' successfully."
+ return 0
+ fi
+
+ timeout=$((3**$retries-1))
+ echo "Failed to execute '$@'. Waiting $timeout seconds before next attempt ($retries out of $maxRetries)." 1>&2
+ sleep $timeout
+ done
+
+ echo "Failed to execute '$@' for $maxRetries times." 1>&2
+
+ return 1
+}
+
+function GetDotNetInstallScript {
+ local root=$1
+ local install_script="$root/dotnet-install.sh"
+ local install_script_url="https://dotnet.microsoft.com/download/dotnet/scripts/$dotnetInstallScriptVersion/dotnet-install.sh"
+
+ if [[ ! -a "$install_script" ]]; then
+ mkdir -p "$root"
+
+ echo "Downloading '$install_script_url'"
+
+ # Use curl if available, otherwise use wget
+ if command -v curl > /dev/null; then
+ # first, try directly, if this fails we will retry with verbose logging
+ curl "$install_script_url" -sSL --retry 10 --create-dirs -o "$install_script" || {
+ if command -v openssl &> /dev/null; then
+ echo "Curl failed; dumping some information about dotnet.microsoft.com for later investigation"
+ echo | openssl s_client -showcerts -servername dotnet.microsoft.com -connect dotnet.microsoft.com:443
+ fi
+ echo "Will now retry the same URL with verbose logging."
+ with_retries curl "$install_script_url" -sSL --verbose --retry 10 --create-dirs -o "$install_script" || {
+ local exit_code=$?
+ Write-PipelineTelemetryError -category 'InitializeToolset' "Failed to acquire dotnet install script (exit code '$exit_code')."
+ ExitWithExitCode $exit_code
+ }
+ }
+ else
+ with_retries wget -v -O "$install_script" "$install_script_url" || {
+ local exit_code=$?
+ Write-PipelineTelemetryError -category 'InitializeToolset' "Failed to acquire dotnet install script (exit code '$exit_code')."
+ ExitWithExitCode $exit_code
+ }
+ fi
+ fi
+ # return value
+ _GetDotNetInstallScript="$install_script"
+}
+
+function InitializeBuildTool {
+ if [[ -n "${_InitializeBuildTool:-}" ]]; then
+ return
+ fi
+
+ InitializeDotNetCli $restore
+
+ # return values
+ _InitializeBuildTool="$_InitializeDotNetCli/dotnet"
+ _InitializeBuildToolCommand="msbuild"
+ _InitializeBuildToolFramework="netcoreapp3.1"
+}
+
+# Set RestoreNoCache as a workaround for https://github.com/NuGet/Home/issues/3116
+function GetNuGetPackageCachePath {
+ if [[ -z ${NUGET_PACKAGES:-} ]]; then
+ if [[ "$use_global_nuget_cache" == true ]]; then
+ export NUGET_PACKAGES="$HOME/.nuget/packages"
+ else
+ export NUGET_PACKAGES="$repo_root/.packages"
+ export RESTORENOCACHE=true
+ fi
+ fi
+
+ # return value
+ _GetNuGetPackageCachePath=$NUGET_PACKAGES
+}
+
+function InitializeNativeTools() {
+ if [[ -n "${DisableNativeToolsetInstalls:-}" ]]; then
+ return
+ fi
+ if grep -Fq "native-tools" $global_json_file
+ then
+ local nativeArgs=""
+ if [[ "$ci" == true ]]; then
+ nativeArgs="--installDirectory $tools_dir"
+ fi
+ "$_script_dir/init-tools-native.sh" $nativeArgs
+ fi
+}
+
+function InitializeToolset {
+ if [[ -n "${_InitializeToolset:-}" ]]; then
+ return
+ fi
+
+ GetNuGetPackageCachePath
+
+ ReadGlobalVersion "Microsoft.DotNet.Arcade.Sdk"
+
+ local toolset_version=$_ReadGlobalVersion
+ local toolset_location_file="$toolset_dir/$toolset_version.txt"
+
+ if [[ -a "$toolset_location_file" ]]; then
+ local path=`cat "$toolset_location_file"`
+ if [[ -a "$path" ]]; then
+ # return value
+ _InitializeToolset="$path"
+ return
+ fi
+ fi
+
+ if [[ "$restore" != true ]]; then
+ Write-PipelineTelemetryError -category 'InitializeToolset' "Toolset version $toolset_version has not been restored."
+ ExitWithExitCode 2
+ fi
+
+ local proj="$toolset_dir/restore.proj"
+
+ local bl=""
+ if [[ "$binary_log" == true ]]; then
+ bl="/bl:$log_dir/ToolsetRestore.binlog"
+ fi
+
+ echo '' > "$proj"
+ MSBuild-Core "$proj" $bl /t:__WriteToolsetLocation /clp:ErrorsOnly\;NoSummary /p:__ToolsetLocationOutputFile="$toolset_location_file"
+
+ local toolset_build_proj=`cat "$toolset_location_file"`
+
+ if [[ ! -a "$toolset_build_proj" ]]; then
+ Write-PipelineTelemetryError -category 'Build' "Invalid toolset path: $toolset_build_proj"
+ ExitWithExitCode 3
+ fi
+
+ # return value
+ _InitializeToolset="$toolset_build_proj"
+}
+
+function ExitWithExitCode {
+ if [[ "$ci" == true && "$prepare_machine" == true ]]; then
+ StopProcesses
+ fi
+ exit $1
+}
+
+function StopProcesses {
+ echo "Killing running build processes..."
+ pkill -9 "dotnet" || true
+ pkill -9 "vbcscompiler" || true
+ return 0
+}
+
+function MSBuild {
+ local args=$@
+ if [[ "$pipelines_log" == true ]]; then
+ InitializeBuildTool
+ InitializeToolset
+
+ if [[ "$ci" == true ]]; then
+ export NUGET_PLUGIN_HANDSHAKE_TIMEOUT_IN_SECONDS=20
+ export NUGET_PLUGIN_REQUEST_TIMEOUT_IN_SECONDS=20
+ Write-PipelineSetVariable -name "NUGET_PLUGIN_HANDSHAKE_TIMEOUT_IN_SECONDS" -value "20"
+ Write-PipelineSetVariable -name "NUGET_PLUGIN_REQUEST_TIMEOUT_IN_SECONDS" -value "20"
+ fi
+
+ local toolset_dir="${_InitializeToolset%/*}"
+ # new scripts need to work with old packages, so we need to look for the old names/versions
+ local selectedPath=
+ local possiblePaths=()
+ possiblePaths+=( "$toolset_dir/$_InitializeBuildToolFramework/Microsoft.DotNet.ArcadeLogging.dll" )
+ possiblePaths+=( "$toolset_dir/$_InitializeBuildToolFramework/Microsoft.DotNet.Arcade.Sdk.dll" )
+ possiblePaths+=( "$toolset_dir/netcoreapp2.1/Microsoft.DotNet.ArcadeLogging.dll" )
+ possiblePaths+=( "$toolset_dir/netcoreapp2.1/Microsoft.DotNet.Arcade.Sdk.dll" )
+ for path in "${possiblePaths[@]}"; do
+ if [[ -f $path ]]; then
+ selectedPath=$path
+ break
+ fi
+ done
+ if [[ -z "$selectedPath" ]]; then
+ Write-PipelineTelemetryError -category 'Build' "Unable to find arcade sdk logger assembly."
+ ExitWithExitCode 1
+ fi
+ args+=( "-logger:$selectedPath" )
+ fi
+
+ MSBuild-Core ${args[@]}
+}
+
+function MSBuild-Core {
+ if [[ "$ci" == true ]]; then
+ if [[ "$binary_log" != true && "$exclude_ci_binary_log" != true ]]; then
+ Write-PipelineTelemetryError -category 'Build' "Binary log must be enabled in CI build, or explicitly opted-out from with the -noBinaryLog switch."
+ ExitWithExitCode 1
+ fi
+
+ if [[ "$node_reuse" == true ]]; then
+ Write-PipelineTelemetryError -category 'Build' "Node reuse must be disabled in CI build."
+ ExitWithExitCode 1
+ fi
+ fi
+
+ InitializeBuildTool
+
+ local warnaserror_switch=""
+ if [[ $warn_as_error == true ]]; then
+ warnaserror_switch="/warnaserror"
+ fi
+
+ function RunBuildTool {
+ export ARCADE_BUILD_TOOL_COMMAND="$_InitializeBuildTool $@"
+
+ "$_InitializeBuildTool" "$@" || {
+ local exit_code=$?
+ # We should not Write-PipelineTaskError here because that message shows up in the build summary
+ # The build already logged an error, that's the reason it failed. Producing an error here only adds noise.
+ echo "Build failed with exit code $exit_code. Check errors above."
+ if [[ "$ci" == "true" ]]; then
+ Write-PipelineSetResult -result "Failed" -message "msbuild execution failed."
+ # Exiting with an exit code causes the azure pipelines task to log yet another "noise" error
+ # The above Write-PipelineSetResult will cause the task to be marked as failure without adding yet another error
+ ExitWithExitCode 0
+ else
+ ExitWithExitCode $exit_code
+ fi
+ }
+ }
+
+ RunBuildTool "$_InitializeBuildToolCommand" /m /nologo /clp:Summary /v:$verbosity /nr:$node_reuse $warnaserror_switch /p:TreatWarningsAsErrors=$warn_as_error /p:ContinuousIntegrationBuild=$ci "$@"
+}
+
+ResolvePath "${BASH_SOURCE[0]}"
+_script_dir=`dirname "$_ResolvePath"`
+
+. "$_script_dir/pipeline-logging-functions.sh"
+
+eng_root=`cd -P "$_script_dir/.." && pwd`
+repo_root=`cd -P "$_script_dir/../.." && pwd`
+repo_root="${repo_root}/"
+artifacts_dir="${repo_root}artifacts"
+toolset_dir="$artifacts_dir/toolset"
+tools_dir="${repo_root}.tools"
+log_dir="$artifacts_dir/log/$configuration"
+temp_dir="$artifacts_dir/tmp/$configuration"
+
+global_json_file="${repo_root}global.json"
+# determine if global.json contains a "runtimes" entry
+global_json_has_runtimes=false
+if command -v jq &> /dev/null; then
+ if jq -er '. | select(has("runtimes"))' "$global_json_file" &> /dev/null; then
+ global_json_has_runtimes=true
+ fi
+elif [[ "$(cat "$global_json_file")" =~ \"runtimes\"[[:space:]\:]*\{ ]]; then
+ global_json_has_runtimes=true
+fi
+
+# HOME may not be defined in some scenarios, but it is required by NuGet
+if [[ -z $HOME ]]; then
+ export HOME="${repo_root}artifacts/.home/"
+ mkdir -p "$HOME"
+fi
+
+mkdir -p "$toolset_dir"
+mkdir -p "$temp_dir"
+mkdir -p "$log_dir"
+
+Write-PipelineSetVariable -name "Artifacts" -value "$artifacts_dir"
+Write-PipelineSetVariable -name "Artifacts.Toolset" -value "$toolset_dir"
+Write-PipelineSetVariable -name "Artifacts.Log" -value "$log_dir"
+Write-PipelineSetVariable -name "Temp" -value "$temp_dir"
+Write-PipelineSetVariable -name "TMP" -value "$temp_dir"
+
+# Import custom tools configuration, if present in the repo.
+if [ -z "${disable_configure_toolset_import:-}" ]; then
+ configure_toolset_script="$eng_root/configure-toolset.sh"
+ if [[ -a "$configure_toolset_script" ]]; then
+ . "$configure_toolset_script"
+ fi
+fi
+
+# TODO: https://github.com/dotnet/arcade/issues/1468
+# Temporary workaround to avoid breaking change.
+# Remove once repos are updated.
+if [[ -n "${useInstalledDotNetCli:-}" ]]; then
+ use_installed_dotnet_cli="$useInstalledDotNetCli"
+fi
diff --git a/eng/publishing/v3/common-variables.yml b/eng/publishing/v3/common-variables.yml
new file mode 100644
index 000000000..ed518e46b
--- /dev/null
+++ b/eng/publishing/v3/common-variables.yml
@@ -0,0 +1,24 @@
+variables:
+ - group: AzureDevOps-Artifact-Feeds-Pats
+ - group: DotNet-Blob-Feed
+ - group: DotNet-DotNetCli-Storage
+ - group: DotNet-MSRC-Storage
+ - group: Publish-Build-Assets
+
+ # Default Maestro++ API Endpoint and API Version
+ - name: MaestroApiEndPoint
+ value: "https://maestro-prod.westus2.cloudapp.azure.com"
+ - name: MaestroApiAccessToken
+ value: $(MaestroAccessToken)
+ - name: MaestroApiVersion
+ value: "2020-02-20"
+
+ - name: SourceLinkCLIVersion
+ value: 3.0.0
+
+ # Skip component governance and codesign validation for SDL. These jobs
+ # create no content.
+ - name: skipComponentGovernanceDetection
+ value: true
+ - name: runCodesignValidationInjection
+ value: false
\ No newline at end of file
diff --git a/eng/publishing/v3/nuget-validation.yml b/eng/publishing/v3/nuget-validation.yml
new file mode 100644
index 000000000..6c9e0b8c3
--- /dev/null
+++ b/eng/publishing/v3/nuget-validation.yml
@@ -0,0 +1,54 @@
+jobs:
+- job:
+ displayName: NuGet Validation
+ dependsOn: setupMaestroVars
+ pool:
+ vmImage: 'windows-2019'
+ variables:
+ - name: AzDOProjectName
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ]
+ - name: AzDOPipelineId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ]
+ - name: AzDOBuildId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ]
+ steps:
+ - task: DownloadBuildArtifacts@0
+ displayName: Download Package Artifacts
+ inputs:
+ buildType: specific
+ buildVersionToDownload: specific
+ project: $(AzDOProjectName)
+ pipeline: $(AzDOPipelineId)
+ buildId: $(AzDOBuildId)
+ artifactName: PackageArtifacts
+ checkDownloadedFiles: true
+
+ - task: PowerShell@2
+ displayName: Validate
+ inputs:
+ targetType: inline
+ script: |
+ try {
+ $ErrorActionPreference = 'Stop'
+ Set-StrictMode -Version 2.0
+
+ # `tools.ps1` requires $ci to be $true
+ $ci = $true
+ $disableConfigureToolsetImport = $true
+ . ${Env:BUILD_SOURCESDIRECTORY}\eng\common\tools.ps1
+
+ $ToolDestinationPath = "${Env:AGENT_BUILDDIRECTORY}\Extract\"
+ $PackagesPath = "${Env:BUILD_ARTIFACTSTAGINGDIRECTORY}\PackageArtifacts\"
+ $url = 'https://raw.githubusercontent.com/NuGet/NuGetGallery/3e25ad135146676bcab0050a516939d9958bfa5d/src/VerifyMicrosoftPackage/verify.ps1'
+
+ New-Item -ItemType 'directory' -Path ${ToolDestinationPath} -Force
+
+ Invoke-WebRequest $url -OutFile ${ToolDestinationPath}\verify.ps1
+
+ & ${ToolDestinationPath}\verify.ps1 ${PackagesPath}\*.nupkg
+ }
+ catch {
+ Write-Host $_.ScriptStackTrace
+ Write-PipelineTelemetryError -Category 'NuGetValidation' -Message $_
+ ExitWithExitCode 1
+ }
diff --git a/eng/publishing/v3/postbuild-checks.yml b/eng/publishing/v3/postbuild-checks.yml
new file mode 100644
index 000000000..9382a1a40
--- /dev/null
+++ b/eng/publishing/v3/postbuild-checks.yml
@@ -0,0 +1,9 @@
+jobs:
+- job:
+ displayName: Post-build Checks
+ dependsOn: setupMaestroVars
+ variables:
+ - name: TargetChannels
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.TargetChannels'] ]
+ pool:
+ vmImage: 'windows-2019'
diff --git a/eng/publishing/v3/publish-assets.yml b/eng/publishing/v3/publish-assets.yml
new file mode 100644
index 000000000..17c85fba2
--- /dev/null
+++ b/eng/publishing/v3/publish-assets.yml
@@ -0,0 +1,100 @@
+parameters:
+ artifactsPublishingAdditionalParameters: ''
+ publishInstallersAndChecksums: true
+ PromoteToChannelIds: ''
+ symbolPublishingAdditionalParameters: ''
+ buildQuality: 'daily'
+
+jobs:
+- job: publish_assets
+ displayName: Publish Assets and Symbols
+ dependsOn: setupMaestroVars
+ timeoutInMinutes: 120
+ variables:
+ - group: DotNet-Symbol-Server-Pats
+ - name: BARBuildId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.BARBuildId'] ]
+ - name: IsStableBuild
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.IsStableBuild'] ]
+ - name: AzDOProjectName
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ]
+ - name: AzDOPipelineId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ]
+ - name: AzDOBuildId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ]
+ - name: AzDOAccount
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildAccount'] ]
+ pool:
+ vmImage: 'windows-2019'
+ steps:
+ - task: DownloadBuildArtifacts@0
+ displayName: Download Build Assets
+ continueOnError: true
+ enabled: true
+ inputs:
+ buildType: specific
+ buildVersionToDownload: specific
+ project: $(AzDOProjectName)
+ pipeline: $(AzDOPipelineId)
+ buildId: $(AzDOBuildId)
+ downloadType: 'specific'
+ itemPattern: |
+ AssetManifests/**
+ BlobArtifacts/MergedManifest.xml
+ PdbArtifacts/**
+ downloadPath: '$(Build.ArtifactStagingDirectory)'
+
+ - task: NuGetToolInstaller@1
+ displayName: 'Install NuGet.exe'
+
+ # This is necessary whenever we want to publish/restore to an AzDO private feed
+ - task: NuGetAuthenticate@0
+ displayName: 'Authenticate to AzDO Feeds'
+
+ - task: PowerShell@2
+ displayName: Enable cross-org publishing
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/enable-cross-org-publishing.ps1
+ arguments: -token $(dn-bot-dnceng-artifact-feeds-rw)
+
+ - task: PowerShell@2
+ displayName: Publish packages, blobs and symbols
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/sdk-task.ps1
+ arguments: -task PublishArtifactsInManifest -restore -msbuildEngine dotnet
+ /p:PublishingInfraVersion=3
+ /p:BARBuildId=$(BARBuildId)
+ /p:TargetChannels='${{ parameters.PromoteToChannelIds }}'
+ /p:IsInternalBuild=${{ and(ne(variables['System.TeamProject'], 'public'), contains(variables['Build.SourceBranch'], 'internal')) }}
+ /p:NugetPath=$(NuGetExeToolPath)
+ /p:MaestroApiEndpoint='$(MaestroApiEndPoint)'
+ /p:BuildAssetRegistryToken='$(MaestroApiAccessToken)'
+ /p:ManifestsBasePath='$(Build.ArtifactStagingDirectory)/AssetManifests/'
+ /p:BlobBasePath='$(Build.ArtifactStagingDirectory)/BlobArtifacts/'
+ /p:PackageBasePath='$(Build.ArtifactStagingDirectory)/PackageArtifacts/'
+ /p:PublishInstallersAndChecksums=${{ parameters.publishInstallersAndChecksums }}
+ /p:InstallersAzureAccountKey=$(dotnetcli-storage-key)
+ /p:InternalInstallersAzureAccountKey=$(dotnetclimsrc-access-key)
+ /p:ChecksumsAzureAccountKey=$(dotnetclichecksums-storage-key)
+ /p:InternalChecksumsAzureAccountKey=$(dotnetclichecksumsmsrc-storage-key)
+ /p:AzureDevOpsFeedsKey='$(dn-bot-dnceng-artifact-feeds-rw)'
+ /p:AzureStorageTargetFeedPAT='$(dotnetfeed-storage-access-key-1)'
+ /p:AkaMSClientId=$(akams-client-id)
+ /p:AkaMSClientSecret=$(akams-client-secret)
+ ${{ parameters.artifactsPublishingAdditionalParameters }}
+ /p:PDBArtifactsBasePath='$(Build.ArtifactStagingDirectory)/PDBArtifacts/'
+ /p:SymbolPublishingExclusionsFile='$(Build.SourcesDirectory)/eng/SymbolPublishingExclusionsFile.txt'
+ ${{ parameters.symbolPublishingAdditionalParameters}}
+ /p:MsdlToken=$(microsoft-symbol-server-pat)
+ /p:SymWebToken=$(symweb-symbol-server-pat)
+ /p:BuildQuality='${{ parameters.buildQuality }}'
+ /p:AzdoApiToken='$(dn-bot-all-orgs-build-rw-code-rw)'
+ /p:ArtifactsBasePath='$(Build.ArtifactStagingDirectory)/'
+ /p:BuildId='$(AzDOBuildId)'
+ /p:AzureDevOpsOrg='$(AzDOAccount)'
+ /p:AzureProject='$(AzDOProjectName)'
+ /p:UseStreamingPublishing='true'
+ - template: /eng/common/templates/steps/publish-logs.yml
+ parameters:
+ StageLabel: '${{ parameters.stageName }}'
+ JobLabel: 'AssetsPublishing'
diff --git a/eng/publishing/v3/publish-symbols.yml b/eng/publishing/v3/publish-symbols.yml
new file mode 100644
index 000000000..10196525e
--- /dev/null
+++ b/eng/publishing/v3/publish-symbols.yml
@@ -0,0 +1,65 @@
+parameters:
+ symbolPublishingAdditionalParameters: ''
+
+jobs:
+- job: publish_symbols
+ displayName: Symbols Publishing
+ dependsOn: setupMaestroVars
+ variables:
+ - group: DotNet-Symbol-Server-Pats
+ - name: AzDOProjectName
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ]
+ - name: AzDOPipelineId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ]
+ - name: AzDOBuildId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ]
+ pool:
+ vmImage: 'windows-2019'
+ steps:
+ - task: DownloadBuildArtifacts@0
+ displayName: Download Build Assets
+ continueOnError: true
+ inputs:
+ buildType: specific
+ buildVersionToDownload: specific
+ project: $(AzDOProjectName)
+ pipeline: $(AzDOPipelineId)
+ buildId: $(AzDOBuildId)
+ downloadType: 'specific'
+ itemPattern: |
+ PdbArtifacts/**
+ BlobArtifacts/**
+ downloadPath: '$(Build.ArtifactStagingDirectory)'
+ checkDownloadedFiles: true
+
+ # This is necessary whenever we want to publish/restore to an AzDO private feed
+ # Since sdk-task.ps1 tries to restore packages we need to do this authentication here
+ # otherwise it'll complain about accessing a private feed.
+ - task: NuGetAuthenticate@0
+ displayName: 'Authenticate to AzDO Feeds'
+
+ - task: PowerShell@2
+ displayName: Enable cross-org publishing
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/enable-cross-org-publishing.ps1
+ arguments: -token $(dn-bot-dnceng-artifact-feeds-rw)
+
+ - task: PowerShell@2
+ displayName: Publish
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/sdk-task.ps1
+ arguments: -task PublishToSymbolServers -restore -msbuildEngine dotnet
+ /p:DotNetSymbolServerTokenMsdl=$(microsoft-symbol-server-pat)
+ /p:DotNetSymbolServerTokenSymWeb=$(symweb-symbol-server-pat)
+ /p:PDBArtifactsDirectory='$(Build.ArtifactStagingDirectory)/PDBArtifacts/'
+ /p:BlobBasePath='$(Build.ArtifactStagingDirectory)/BlobArtifacts/'
+ /p:SymbolPublishingExclusionsFile='$(Build.SourcesDirectory)/eng/SymbolPublishingExclusionsFile.txt'
+ /p:Configuration=Release
+ /p:PublishToMSDL=false
+ /p:PublishToSymWeb=true
+ ${{ parameters.symbolPublishingAdditionalParameters }}
+
+ - template: /eng/common/templates/steps/publish-logs.yml
+ parameters:
+ StageLabel: '${{ parameters.stageName }}'
+ JobLabel: 'SymbolPublishing'
diff --git a/eng/publishing/v3/publish.yml b/eng/publishing/v3/publish.yml
new file mode 100644
index 000000000..ef0315cff
--- /dev/null
+++ b/eng/publishing/v3/publish.yml
@@ -0,0 +1,61 @@
+parameters:
+ BARBuildId: ''
+ PromoteToChannelIds: ''
+
+ enableSourceLinkValidation: false
+ enableSigningValidation: true
+ enableNugetValidation: true
+ publishInstallersAndChecksums: true
+
+ # These parameters let the user customize the call to sdk-task.ps1 for publishing
+ # symbols & general artifacts as well as for signing validation
+ symbolPublishingAdditionalParameters: ''
+ artifactsPublishingAdditionalParameters: ''
+ signingValidationAdditionalParameters: ''
+
+ # Which stages should finish execution before post-build stages start
+ validateDependsOn:
+ - build
+ publishDependsOn:
+ - Validate
+
+stages:
+ - stage: Validate
+ dependsOn: ${{ parameters.validateDependsOn }}
+ displayName: Validate Build Assets
+ variables:
+ - template: /eng/publishing/v3/common-variables.yml
+ jobs:
+ - template: /eng/publishing/v3/setup-maestro-vars.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+
+ - template: /eng/publishing/v3/postbuild-checks.yml
+
+ - ${{ if eq(parameters.enableNugetValidation, 'True') }}:
+ - template: /eng/publishing/v3/nuget-validation.yml
+
+ - ${{ if eq(parameters.enableSigningValidation, 'True') }}:
+ - template: /eng/publishing/v3/signing-validation.yml
+
+ - ${{ if eq(parameters.enableSourceLinkValidation, 'True') }}:
+ - template: /eng/publishing/v3/sourcelink-validation.yml
+
+ - stage: publish
+ dependsOn: ${{ parameters.publishDependsOn }}
+ variables:
+ - template: /eng/publishing/v3/common-variables.yml
+ displayName: Publishing
+ jobs:
+ - template: /eng/publishing/v3/setup-maestro-vars.yml
+ parameters:
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+
+ - template: /eng/publishing/v3/publish-assets.yml
+ parameters:
+ PromoteToChannelIds: ${{ parameters.PromoteToChannelIds }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ symbolPublishingAdditionalParameters: ${{parameters.symbolPublishingAdditionalParameters}}
diff --git a/eng/publishing/v3/setup-maestro-vars.yml b/eng/publishing/v3/setup-maestro-vars.yml
new file mode 100644
index 000000000..ae2e65527
--- /dev/null
+++ b/eng/publishing/v3/setup-maestro-vars.yml
@@ -0,0 +1,61 @@
+parameters:
+ BARBuildId: ''
+ PromoteToChannelIds: ''
+
+jobs:
+- job: setupMaestroVars
+ displayName: Setup Maestro Vars
+ variables:
+ - template: /eng/publishing/v3/common-variables.yml
+ pool:
+ vmImage: 'windows-2019'
+ steps:
+ - checkout: none
+
+ - task: PowerShell@2
+ name: setReleaseVars
+ displayName: Set Release Configs Vars
+ inputs:
+ targetType: inline
+ script: |
+ try {
+ dir Env:
+
+ $buildApiEndpoint = "${Env:MaestroApiEndPoint}/api/builds/${Env:BARBuildId}?api-version=${Env:MaestroApiVersion}"
+
+ $apiHeaders = New-Object 'System.Collections.Generic.Dictionary[[String],[String]]'
+ $apiHeaders.Add('Accept', 'application/json')
+ $apiHeaders.Add('Authorization',"Bearer ${Env:MAESTRO_API_TOKEN}")
+
+ $buildInfo = try { Invoke-WebRequest -Method Get -Uri $buildApiEndpoint -Headers $apiHeaders | ConvertFrom-Json } catch { Write-Host "Error: $_" }
+
+ $BarId = $Env:BARBuildId
+ $Channels = $Env:PromoteToMaestroChannels -split ","
+ $Channels = $Channels -join "]["
+ $Channels = "[$Channels]"
+
+ $IsStableBuild = $buildInfo.stable
+ $AzureDevOpsProject = $buildInfo.azureDevOpsProject
+ $AzureDevOpsBuildDefinitionId = $buildInfo.azureDevOpsBuildDefinitionId
+ $AzureDevOpsBuildId = $buildInfo.azureDevOpsBuildId
+ $AzureDevOpsAccount = $buildInfo.azureDevOpsAccount
+
+ Write-Host "##vso[task.setvariable variable=BARBuildId;isOutput=true]$BarId"
+ Write-Host "##vso[task.setvariable variable=TargetChannels;isOutput=true]$Channels"
+ Write-Host "##vso[task.setvariable variable=IsStableBuild;isOutput=true]$IsStableBuild"
+
+ Write-Host "##vso[task.setvariable variable=AzDOProjectName;isOutput=true]$AzureDevOpsProject"
+ Write-Host "##vso[task.setvariable variable=AzDOPipelineId;isOutput=true]$AzureDevOpsBuildDefinitionId"
+ Write-Host "##vso[task.setvariable variable=AzDOBuildId;isOutput=true]$AzureDevOpsBuildId"
+ Write-Host "##vso[task.setvariable variable=AzDOBuildAccount;isOutput=true]$AzureDevOpsAccount"
+ }
+ catch {
+ Write-Host $_
+ Write-Host $_.Exception
+ Write-Host $_.ScriptStackTrace
+ exit 1
+ }
+ env:
+ MAESTRO_API_TOKEN: $(MaestroApiAccessToken)
+ BARBuildId: ${{ parameters.BARBuildId }}
+ PromoteToMaestroChannels: ${{ parameters.PromoteToChannelIds }}
diff --git a/eng/publishing/v3/signing-validation.yml b/eng/publishing/v3/signing-validation.yml
new file mode 100644
index 000000000..22611ddff
--- /dev/null
+++ b/eng/publishing/v3/signing-validation.yml
@@ -0,0 +1,56 @@
+jobs:
+- job:
+ displayName: Signing Validation
+ dependsOn: setupMaestroVars
+ variables:
+ - template: /eng/publishing/v3/common-variables.yml
+ - name: AzDOProjectName
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ]
+ - name: AzDOPipelineId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ]
+ - name: AzDOBuildId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ]
+ pool:
+ vmImage: 'windows-2019'
+ steps:
+ - task: DownloadBuildArtifacts@0
+ displayName: Download Package Artifacts
+ inputs:
+ buildType: specific
+ buildVersionToDownload: specific
+ project: $(AzDOProjectName)
+ pipeline: $(AzDOPipelineId)
+ buildId: $(AzDOBuildId)
+ artifactName: PackageArtifacts
+ checkDownloadedFiles: true
+ itemPattern: |
+ **
+ !**/Microsoft.SourceBuild.Intermediate.*.nupkg
+
+ # This is necessary whenever we want to publish/restore to an AzDO private feed
+ # Since sdk-task.ps1 tries to restore packages we need to do this authentication here
+ # otherwise it'll complain about accessing a private feed.
+ - task: NuGetAuthenticate@0
+ displayName: 'Authenticate to AzDO Feeds'
+
+ - task: PowerShell@2
+ displayName: Enable cross-org publishing
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/enable-cross-org-publishing.ps1
+ arguments: -token $(dn-bot-dnceng-artifact-feeds-rw)
+
+ # Signing validation will optionally work with the buildmanifest file which is downloaded from
+ # Azure DevOps above.
+ - task: PowerShell@2
+ displayName: Validate
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/sdk-task.ps1
+ arguments: -task SigningValidation -restore -msbuildEngine vs
+ /p:PackageBasePath='$(Build.ArtifactStagingDirectory)/PackageArtifacts'
+ /p:SignCheckExclusionsFile='$(Build.SourcesDirectory)/eng/SignCheckExclusionsFile.txt'
+ ${{ parameters.signingValidationAdditionalParameters }}
+
+ - template: /eng/common/templates/steps/publish-logs.yml
+ parameters:
+ StageLabel: 'Validation'
+ JobLabel: 'Signing'
diff --git a/eng/publishing/v3/sourcelink-validation.yml b/eng/publishing/v3/sourcelink-validation.yml
new file mode 100644
index 000000000..b290d57e4
--- /dev/null
+++ b/eng/publishing/v3/sourcelink-validation.yml
@@ -0,0 +1,36 @@
+jobs:
+- job:
+ displayName: SourceLink Validation
+ dependsOn: setupMaestroVars
+ variables:
+ - template: /eng/publishing/v3/common-variables.yml
+ - name: AzDOProjectName
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ]
+ - name: AzDOPipelineId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ]
+ - name: AzDOBuildId
+ value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ]
+ pool:
+ vmImage: 'windows-2019'
+ steps:
+ - task: DownloadBuildArtifacts@0
+ displayName: Download Blob Artifacts
+ inputs:
+ buildType: specific
+ buildVersionToDownload: specific
+ project: $(AzDOProjectName)
+ pipeline: $(AzDOPipelineId)
+ buildId: $(AzDOBuildId)
+ artifactName: BlobArtifacts
+ checkDownloadedFiles: true
+
+ - task: PowerShell@2
+ displayName: Validate
+ inputs:
+ filePath: $(Build.SourcesDirectory)/eng/common/post-build/sourcelink-validation.ps1
+ arguments: -InputPath $(Build.ArtifactStagingDirectory)/BlobArtifacts/
+ -ExtractPath $(Agent.BuildDirectory)/Extract/
+ -GHRepoName $(Build.Repository.Name)
+ -GHCommit $(Build.SourceVersion)
+ -SourcelinkCliVersion $(SourceLinkCLIVersion)
+ continueOnError: true
diff --git a/global.json b/global.json
new file mode 100644
index 000000000..80304e5d6
--- /dev/null
+++ b/global.json
@@ -0,0 +1,18 @@
+{
+ "tools": {
+ "vs": {
+ "version": "16.0",
+ "components": [
+ "Microsoft.Net.Component.4.5.2.TargetingPack",
+ "Microsoft.VisualStudio.Windows.Build",
+ "Microsoft.VisualStudio.Component.VSSDK"
+ ]
+ },
+ "dotnet": "6.0.100-preview.4.21255.9",
+ "vswhere": "2.5.2"
+ },
+ "msbuild-sdks": {
+ "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21369.3",
+ "Microsoft.DotNet.Helix.Sdk": "6.0.0-beta.21369.3"
+ }
+}
diff --git a/samples/FxExtensibility/FxExtensibility.csproj b/samples/FxExtensibility/FxExtensibility.csproj
index 7085c3cff..deda03426 100644
--- a/samples/FxExtensibility/FxExtensibility.csproj
+++ b/samples/FxExtensibility/FxExtensibility.csproj
@@ -1,9 +1,7 @@
-
- ..\..\
-
-
+
+
Debug
AnyCPU
@@ -14,7 +12,9 @@
MSTest.Extensibility.Samples
v4.5.2
512
+ PackageReference
+
true
full
@@ -39,10 +39,11 @@
-
+
{7252d9e3-267d-442c-96bc-c73aef3241d6}
MSTest.Core
-
+
+
\ No newline at end of file
diff --git a/scripts/Build.ps1 b/scripts/Build.ps1
index 2f6aa55ed..80a1b4f3b 100644
--- a/scripts/Build.ps1
+++ b/scripts/Build.ps1
@@ -82,22 +82,6 @@ $TFB_Solutions = @(
"TestFx.sln"
)
-$TFB_NetCoreProjects = @(
- "src\Adapter\PlatformServices.NetCore\PlatformServices.NetCore.csproj"
-
- "test\ComponentTests\TestAssets\TestProjectForAssemblyResolution\TestProjectForAssemblyResolution.csproj"
- "test\E2ETests\TestAssets\CompatTestProject\CompatTestProject.csproj"
- "test\E2ETests\TestAssets\DataRowTestProject\DataRowTestProject.csproj"
- "test\E2ETests\TestAssets\DataSourceTestProject\DataSourceTestProject.csproj"
- "test\E2ETests\TestAssets\DeploymentTestProject\DeploymentTestProject.csproj"
- "test\E2ETests\TestAssets\DeploymentTestProjectNetCore\DeploymentTestProjectNetCore.csproj"
- "test\E2ETests\TestAssets\DoNotParallelizeTestProject\DoNotParallelizeTestProject.csproj"
- "test\E2ETests\TestAssets\FSharpTestProject\FSharpTestProject.fsproj"
- "test\E2ETests\TestAssets\TimeoutTestProject\TimeoutTestProject.csproj"
- "test\E2ETests\TestAssets\TimeoutTestProjectNetCore\TimeoutTestProjectNetCore.csproj"
- "test\UnitTests\PlatformServices.NetCore.Unit.Tests\PlatformServices.NetCore.Unit.Tests.csproj"
-)
-
#
# Script Preferences
#
@@ -136,6 +120,25 @@ function Print-Help {
Exit 0
}
+function Install-WindowsSDK {
+ Push-Location
+ $temp = [System.IO.Path]::GetTempFileName();
+ Remove-Item $temp
+ New-Item $temp -Type Directory | Out-Null
+ Set-Location $temp
+
+ try {
+ Invoke-WebRequest -Method Get -Uri https://go.microsoft.com/fwlink/p/?LinkId=838916 -OutFile sdksetup.exe -UseBasicParsing
+ Start-Process -Wait sdksetup.exe -ArgumentList "/q", "/norestart", "/ceip off", "/features OptionId.WindowsSoftwareDevelopmentKit" -Wait -PassThru
+ }
+ finally {
+ Pop-Location
+
+ Remove-Item $temp -Force -Recurse | Out-Null
+ }
+
+}
+
#
# Restores packages for the solutions.
#
@@ -151,46 +154,16 @@ function Perform-Restore {
$nuget = Locate-NuGet
$nugetConfig = Locate-NuGetConfig
- $toolset = Locate-Toolset
-
+ $toolset = ".\scripts\Toolset\tools.proj"
if ($TFB_ClearPackageCache) {
- Write-Log " Clearing local package cache..."
+ Write-Log "Clearing local package cache..."
& $nuget locals all -clear
}
- Write-Log " Starting toolset restore..."
- Write-Verbose "$nuget restore -msbuildVersion $msbuildVersion -verbosity normal -nonInteractive -configFile $nugetConfig $toolset"
- & $nuget restore -msbuildVersion $msbuildVersion -verbosity normal -nonInteractive -configFile $nugetConfig $toolset
-
- if ($lastExitCode -ne 0) {
- throw "The restore failed with an exit code of '$lastExitCode'."
- }
-
- Write-Verbose "Locating MSBuild install path..."
- $msbuildPath = Locate-MSBuildPath
-
- Write-Verbose "Starting solution restore..."
- foreach ($solution in $TFB_Solutions) {
- $solutionPath = Locate-Item -relativePath $solution
-
- Write-Verbose "$nuget restore -msbuildPath $msbuildPath -verbosity quiet -nonInteractive -configFile $nugetConfig $solutionPath"
- & $nuget restore -msbuildPath $msbuildPath -verbosity quiet -nonInteractive -configFile $nugetConfig $solutionPath
- }
-
- if ($lastExitCode -ne 0) {
- throw "The restore failed with an exit code of '$lastExitCode'."
- }
-
- $msbuild = Join-Path $msbuildPath "MSBuild.exe"
-
- Write-Verbose "Starting restore for NetCore Projects"
- foreach ($project in $TFB_NetCoreProjects) {
- $projectPath = Locate-Item -relativePath $project
+ Write-Log "Starting toolset restore..."
+ Write-Verbose "$nuget restore -verbosity normal -nonInteractive -configFile $nugetConfig $toolset"
+ & $nuget restore -verbosity normal -nonInteractive -configFile $nugetConfig $toolset
- Write-Verbose "$msbuild /t:restore -verbosity:minimal $projectPath /m"
- & $msbuild /t:restore -verbosity:minimal $projectPath /m
- }
-
if ($lastExitCode -ne 0) {
throw "The restore failed with an exit code of '$lastExitCode'."
}
@@ -219,22 +192,37 @@ function Perform-Build {
}
}
- Invoke-Build -solution "TestFx.sln"
+ Invoke-MSBuild -solution "TestFx.sln"
Write-Log "Perform-Build: Completed. {$(Get-ElapsedTime($timer))}"
}
-function Invoke-Build([string] $solution, $hasVsixExtension = "false") {
+function Invoke-MSBuild([string]$solution, $buildTarget = $Target, $hasVsixExtension = "false", [switch]$NoRestore) {
$msbuild = Locate-MSBuild -hasVsixExtension $hasVsixExtension
$solutionPath = Locate-Item -relativePath $solution
- $solutionDir = [System.IO.Path]::GetDirectoryName($solutionPath)
- $solutionSummaryLog = Join-Path -path $solutionDir -childPath "msbuild.log"
- $solutionWarningLog = Join-Path -path $solutionDir -childPath "msbuild.wrn"
- $solutionFailureLog = Join-Path -path $solutionDir -childPath "msbuild.err"
-
- Write-Log " Building $solution..."
- Write-Verbose "$msbuild /t:$Target /p:Configuration=$configuration /v:m /flp1:Summary`;Verbosity=diagnostic`;Encoding=UTF-8`;LogFile=$solutionSummaryLog /flp2:WarningsOnly`;Verbosity=diagnostic`;Encoding=UTF-8`;LogFile=$solutionWarningLog /flp3:ErrorsOnly`;Verbosity=diagnostic`;Encoding=UTF-8`;LogFile=$solutionFailureLog /p:IsLocalizedBuild=$TFB_IsLocalizedBuild /p:UpdateXlf=$TFB_UpdateXlf /p:BuildVersion=$TFB_BuildVersion $solutionPath /bl /m"
- & $msbuild /t:$Target /p:Configuration=$configuration /v:m /flp1:Summary`;Verbosity=diagnostic`;Encoding=UTF-8`;LogFile=$solutionSummaryLog /flp2:WarningsOnly`;Verbosity=diagnostic`;Encoding=UTF-8`;LogFile=$solutionWarningLog /flp3:ErrorsOnly`;Verbosity=diagnostic`;Encoding=UTF-8`;LogFile=$solutionFailureLog /p:IsLocalizedBuild=$TFB_IsLocalizedBuild /p:UpdateXlf=$TFB_UpdateXlf /p:BuildVersion=$TFB_BuildVersion $solutionPath /bl /m
+ $logsDir = Get-LogsPath
+
+ $fileName = [System.IO.Path]::GetFileNameWithoutExtension($solution)
+ $binLog = Join-Path -path $logsDir -childPath "$fileName.$buildTarget.binlog"
+
+ $restore = "True"
+ if($NoRestore) {
+ $restore = "False"
+ }
+
+ $argument = @("-t:$buildTarget",
+ "-p:Configuration=$configuration",
+ "-v:m",
+ "-p:IsLocalizedBuild=$TFB_IsLocalizedBuild",
+ "-p:UpdateXlf=$TFB_UpdateXlf",
+ "-p:BuildVersion=$TFB_BuildVersion",
+ "-restore:$restore",
+ "`"$solutionPath`"",
+ "-bl:`"$binLog`"",
+ "-m")
+
+ Write-Log " $buildTarget`: $solution..."
+ & "$msbuild" $argument;
if ($lastExitCode -ne 0) {
throw "Build failed with an exit code of '$lastExitCode'."
@@ -271,10 +259,6 @@ function Create-NugetPackages {
Copy-Item -Path "$($env:TF_PACKAGES_DIR)\microsoft.testplatform.adapterutilities\$TestPlatformVersion\lib" -Destination "$($stagingDir)\Microsoft.TestPlatform.AdapterUtilities" -Recurse -Force
- # Copy over LICENSE file to staging directory
- $licenseFilePath = Join-Path $env:TF_ROOT_DIR "LICENSE"
- Copy-Item $licenseFilePath $stagingDir -Force
-
# Call nuget pack on these components.
$nugetExe = Locate-Nuget
@@ -300,34 +284,6 @@ function Create-NugetPackages {
Write-Log "Create-NugetPackages: Complete. {$(Get-ElapsedTime($timer))}"
}
-function Replace-InFile($File, $RegEx, $ReplaceWith) {
- $content = Get-Content -Raw -Encoding utf8 $File
- $newContent = ($content -replace $RegEx, $ReplaceWith)
- if (-not $content.Equals($newContent)) {
- Write-Log "Updating TestPlatform version in $File"
- $newContent | Set-Content -Encoding utf8 $File -NoNewline
- }
-}
-
-function Sync-PackageVersions {
- $versionsRegex = '(?mi)<(TestPlatformVersion.*?)>(.*?)<\/TestPlatformVersion>'
- $packageRegex = '(?mi)$TestPlatformVersion"
- }
-
- (Get-ChildItem "$PSScriptRoot\..\src\*packages.config", "$PSScriptRoot\..\test\*packages.config" -Recurse) | ForEach-Object {
- Replace-InFile -File $_ -RegEx $packageRegex -ReplaceWith ('
-
-
-
+
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
+
-
+
-
+
-
+
- <_SourcePath>$(TestFxPackagesRoot)MSTest.Internal.TestFx.Localized.Documentation.1.0.0-build-20170420-1\contentFiles\any\any\$(LocDocumentationSubPath)
+ <_SourcePath>$(NuGetPackageRoot)\MSTest.Internal.TestFx.Localized.Documentation\$(MsTestInternalTestFxLocalizedDocumentationVersion)\contentFiles\any\any\$(LocDocumentationSubPath)
<_LocalizedFiles Include="$(_SourcePath)\**\*.*" />
@@ -80,9 +80,17 @@
-
+
-
+
+
+
+
diff --git a/scripts/build/TestFx.Settings.targets b/scripts/build/TestFx.Settings.targets
deleted file mode 100644
index 2f53ecce3..000000000
--- a/scripts/build/TestFx.Settings.targets
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
- ..\..\
- $(MSBuildThisFileDirectory)..\..\
- true
-
-
-
-
-
-
-
-
- Debug
- AnyCPU
- en-US
- 512
- true
- $(MSBuildThisFileDirectory)key.snk
- true
- true
-
- true
- $(TestFxRoot)artifacts\$(Configuration)\$(MSBuildProjectName)\
- $(TestFxRoot)artifacts\$(Configuration)\$(MSBuildProjectName)\obj\
- true
-
-
-
- true
-
-
-
-
- false
- $(MSBuildThisFileDirectory)stylecop.ruleset
- $(MSBuildThisFileDirectory)stylecop.test.ruleset
-
-
\ No newline at end of file
diff --git a/scripts/build/TestFx.Versions.targets b/scripts/build/TestFx.Versions.targets
deleted file mode 100644
index 4e3fe47b7..000000000
--- a/scripts/build/TestFx.Versions.targets
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
- 16.9.1
- 11.0
-
-
\ No newline at end of file
diff --git a/scripts/build/TestFx.props b/scripts/build/TestFx.props
new file mode 100644
index 000000000..ddc819bce
--- /dev/null
+++ b/scripts/build/TestFx.props
@@ -0,0 +1,37 @@
+
+
+
+ $([MSBuild]::NormalizeDirectory('$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), 'LICENSE'))'))
+ $(RepoRoot)artifacts\$(Configuration)\
+ true
+
+
+
+
+
+ Debug
+ AnyCPU
+ en-US
+ 512
+ true
+ $(MSBuildThisFileDirectory)key.snk
+ true
+ true
+
+ true
+ $(RepoRoot)artifacts\$(Configuration)\$(MSBuildProjectName)\
+ $(RepoRoot)artifacts\$(Configuration)\$(MSBuildProjectName)\obj\
+ true
+
+
+
+ true
+
+
+
+
+ false
+ $(MSBuildThisFileDirectory)stylecop.ruleset
+ $(MSBuildThisFileDirectory)stylecop.test.ruleset
+
+
\ No newline at end of file
diff --git a/scripts/build/TestFx.targets b/scripts/build/TestFx.targets
index 3156375e2..c6155c40f 100644
--- a/scripts/build/TestFx.targets
+++ b/scripts/build/TestFx.targets
@@ -1,21 +1,7 @@
-
-
-
-
-
- ..\..\
- ..\..\
- $(TestFxRoot)packages\
- true
-
-
-
-
-
-
+
@@ -25,19 +11,19 @@
-
-
+
+
stylecop.json
-
-
-
+
+
+
-
-
+
+
Microsoft400
StrongName
@@ -48,14 +34,6 @@
-
-
- This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
-
-
-
-
-
@@ -84,7 +62,7 @@
-
+
diff --git a/scripts/common.lib.ps1 b/scripts/common.lib.ps1
index d63a78aeb..6f7b4714c 100644
--- a/scripts/common.lib.ps1
+++ b/scripts/common.lib.ps1
@@ -3,26 +3,39 @@
# Common utilities for building solution and running tests
+$TF_ROOT_DIR = (Get-Item (Split-Path $MyInvocation.MyCommand.Path)).Parent.FullName
+$TF_VERSIONS_FILE = "$TF_ROOT_DIR\eng\Versions.props"
+$TF_OUT_DIR = Join-Path $TF_ROOT_DIR "artifacts"
+$TF_SRC_DIR = Join-Path $TF_ROOT_DIR "src"
+$TF_TEST_DIR = Join-Path $TF_ROOT_DIR "test"
+$TF_PACKAGES_DIR = Join-Path $TF_ROOT_DIR "packages"
+$TF_TOOLS_DIR = Join-Path $TF_ROOT_DIR "tools"
+
+function Get-PackageVersion ([string]$PackageName) {
+ $packages = ([XML](Get-Content $TF_VERSIONS_FILE)).Project.PropertyGroup
+
+ return $packages[$PackageName].InnerText;
+}
+
#
# Global Variables
#
-$global:msbuildVersion = "15.0"
-$global:nugetVersion = "5.8.1"
-$global:vswhereVersion = "2.0.2"
-$global:nugetUrl = "https://dist.nuget.org/win-x86-commandline/v$nugetVersion/NuGet.exe"
+$global:nugetVersion = Get-PackageVersion -PackageName "NuGetFrameworksVersion"
+$global:vswhereVersion = Get-PackageVersion -PackageName "VsWhereVersion"
#
# Global Environment Variables
#
-$env:TF_ROOT_DIR = (Get-Item (Split-Path $MyInvocation.MyCommand.Path)).Parent.FullName
-$env:TF_OUT_DIR = Join-Path $env:TF_ROOT_DIR "artifacts"
-$env:TF_SRC_DIR = Join-Path $env:TF_ROOT_DIR "src"
-$env:TF_TEST_DIR = Join-Path $env:TF_ROOT_DIR "test"
-$env:TF_PACKAGES_DIR = Join-Path $env:TF_ROOT_DIR "packages"
+$env:TF_ROOT_DIR = $TF_ROOT_DIR
+$env:TF_OUT_DIR = $TF_OUT_DIR
+$env:TF_SRC_DIR = $TF_SRC_DIR
+$env:TF_TEST_DIR = $TF_TEST_DIR
+$env:TF_PACKAGES_DIR = $TF_PACKAGES_DIR
+$env:TF_TOOLS_DIR = $TF_TOOLS_DIR
+$env:DOTNET_CLI_VERSION = "6.0.100-alpha.1.21067.8"
-$TF_VERSIONS_FILE = "$PSScriptRoot\build\TestFx.Versions.targets"
if ([String]::IsNullOrWhiteSpace($TestPlatformVersion)) {
- $TestPlatformVersion = (([XML](Get-Content $TF_VERSIONS_FILE)).Project.PropertyGroup.TestPlatformVersion).InnerText
+ $TestPlatformVersion = Get-PackageVersion -PackageName "MicrosoftNETTestSdkVersion"
}
function Create-Directory([string[]] $path) {
@@ -50,7 +63,7 @@ function Locate-MSBuild($hasVsixExtension = "false") {
$msbuild = Join-Path -path $msbuildPath -childPath "MSBuild.exe"
if (!(Test-Path -path $msbuild)) {
- throw "The specified MSBuild version ($msbuildVersion) could not be located."
+ throw "The specified MSBuild could not be located."
}
return Resolve-Path -path $msbuild
@@ -66,7 +79,7 @@ function Locate-MSBuildPath($hasVsixExtension = "false") {
}
catch {
# Resolve-Path throws if the path does not exist, so use the VS2017 path as a fallback
- $msbuildPath = Join-Path -path $vsInstallPath -childPath "MSBuild\$msbuildVersion\Bin"
+ $msbuildPath = Join-Path -path $vsInstallPath -childPath "MSBuild\15.0\Bin"
$msbuildPath = Resolve-Path $msbuildPath
}
@@ -74,7 +87,7 @@ function Locate-MSBuildPath($hasVsixExtension = "false") {
}
function Locate-NuGet {
- $rootPath = $env:TF_ROOT_DIR
+ $rootPath = Join-Path -path $env:TF_PACKAGES_DIR -childPath "toolset"
$nuget = Join-Path -path $rootPath -childPath "nuget.exe"
if (Test-Path -path $nuget) {
@@ -88,7 +101,8 @@ function Locate-NuGet {
Remove-Item -path $nuget | Out-Null
}
- Download-File -address $nugetUrl -fileName $nuget
+ New-Item $rootPath -ItemType Directory | Out-Null
+ Download-File -address "https://dist.nuget.org/win-x86-commandline/v$nugetVersion/NuGet.exe" -fileName $nuget
if (!(Test-Path -path $nuget)) {
throw "The specified NuGet version ($nugetVersion) could not be downloaded."
@@ -103,12 +117,6 @@ function Locate-NuGetConfig {
return Resolve-Path -path $nugetConfig
}
-function Locate-Toolset {
- $rootPath = $env:TF_ROOT_DIR
- $toolset = Join-Path -path $rootPath -childPath "scripts\Toolset\packages.config"
- return Resolve-Path -path $toolset
-}
-
function Locate-PackagesPath {
$rootPath = $env:TF_ROOT_DIR
$packagesPath = Join-Path -path $rootPath -childPath "packages"
@@ -120,7 +128,7 @@ function Locate-PackagesPath {
function Locate-VsWhere {
$packagesPath = Locate-PackagesPath
- $vswhere = Join-Path -path $packagesPath -childPath "vswhere.$vswhereVersion\tools\vswhere.exe"
+ $vswhere = Join-Path -path $packagesPath -childPath "vswhere\$vswhereVersion\tools\vswhere.exe"
Write-Verbose "vswhere location is : $vswhere"
return $vswhere
@@ -162,6 +170,24 @@ function Locate-Item([string] $relativePath) {
return Resolve-Path -path $itemPath
}
+function Get-LogsPath {
+ $artifacts = Join-Path -path $TF_OUT_DIR -childPath "logs"
+
+ if (-not (Test-Path $artifacts)) {
+ New-Item -Type Directory -Path $artifacts | Out-Null
+ }
+
+ return $artifacts
+}
+
+function Get-VSTestPath
+{
+ $TestPlatformVersion = Get-PackageVersion -PackageName "MicrosoftNETTestSdkVersion"
+ $vstestPath = Join-Path -path (Locate-PackagesPath) "Microsoft.TestPlatform\$TestPlatformVersion\tools\net451\Common7\IDE\Extensions\TestPlatform\vstest.console.exe"
+
+ return Resolve-Path -path $vstestPath
+}
+
function Start-Timer {
return [System.Diagnostics.Stopwatch]::StartNew()
}
@@ -180,6 +206,34 @@ function Write-Log ([string] $message, $messageColor = "Green") {
$Host.UI.RawUI.ForegroundColor = $currentColor
}
+function Replace-InFile($File, $RegEx, $ReplaceWith) {
+ $content = Get-Content -Raw -Encoding utf8 $File
+ $newContent = ($content -replace $RegEx, $ReplaceWith)
+ if (-not $content.Equals($newContent)) {
+ Write-Log "Updating TestPlatform version in $File"
+ $newContent | Set-Content -Encoding utf8 $File -NoNewline
+ }
+}
+
+function Sync-PackageVersions {
+ $versionsRegex = '(?mi)<(MicrosoftNETTestSdkVersion.*?)>(.*?)<\/MicrosoftNETTestSdkVersion>'
+ $packageRegex = '(?mi)$TestPlatformVersion"
+ }
+
+ (Get-ChildItem "$PSScriptRoot\..\src\*packages.config", "$PSScriptRoot\..\test\*packages.config" -Recurse) | ForEach-Object {
+ Replace-InFile -File $_ -RegEx $packageRegex -ReplaceWith ('
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/scripts/toolset/tools.proj b/scripts/toolset/tools.proj
new file mode 100644
index 000000000..53ff31938
--- /dev/null
+++ b/scripts/toolset/tools.proj
@@ -0,0 +1,42 @@
+
+
+ $([MSBuild]::NormalizeDirectory('$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), 'LICENSE'))'))
+
+
+ <_NuGetRestoreTargets Condition="Exists('$(MSBuildToolsPath)\NuGet.targets')" >$(MSBuildToolsPath)\NuGet.targets
+ <_NuGetRestoreTargets Condition="'$([MSBuild]::IsRunningFromVisualStudio())' == 'true' And Exists('$(MSBuildToolsPath32)\..\..\..\Common7\IDE\CommonExtensions\Microsoft\NuGet\NuGet.targets')">$(MSBuildToolsPath32)\..\..\..\Common7\IDE\CommonExtensions\Microsoft\NuGet\NuGet.targets
+
+
+
+
+
+
+ true
+
+
+
+
+ net472
+
+ 5
+ .NETFramework
+ .NETFramework,Version=v4.7.2
+ $(RepoRoot)artifacts\toolset\
+ $(OutputPath)
+
+
+
+
+ $(RepoRoot)NuGet.config
+
+
+
+
+
\ No newline at end of file
diff --git a/scripts/verify-sign.ps1 b/scripts/verify-sign.ps1
index 14ac0a0e0..5f34d6731 100644
--- a/scripts/verify-sign.ps1
+++ b/scripts/verify-sign.ps1
@@ -1,4 +1,6 @@
-# Copyright (c) Microsoft. All rights reserved.
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
# Build script for Test Platform.
[CmdletBinding()]
@@ -33,7 +35,7 @@ function Verify-NugetPackages
$artifactsDirectory = Join-Path $rootDirectory "artifacts"
$artifactsConfigDirectory = Join-Path $artifactsDirectory $TPB_Configuration
$packagesDirectory = Join-Path $artifactsConfigDirectory "MSTestPackages"
- Get-ChildItem -Filter *.nupkg $packagesDirectory | % {
+ Get-ChildItem -Filter *.nupkg $packagesDirectory | ForEach-Object {
& $nugetInstallPath verify -signature -CertificateFingerprint "3F9001EA83C560D712C24CF213C3D312CB3BFF51EE89435D3430BD06B5D0EECE;AA12DA22A49BCE7D5C1AE64CC1F3D892F150DA76140F210ABD2CBFFCA2C18A27;" $_.FullName
}
diff --git a/scripts/write-release-notes.ps1 b/scripts/write-release-notes.ps1
index c4e9b0609..a2332a986 100644
--- a/scripts/write-release-notes.ps1
+++ b/scripts/write-release-notes.ps1
@@ -1,3 +1,6 @@
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
[CmdletBinding()]
param
(
@@ -99,7 +102,7 @@ $issues = $log | ForEach-Object {
$output = @"
-See release notes [here](https://github.com/microsoft/testfx-docs/blob/master/docs/releases.md#$(("$v $date" -replace "\.", "" -replace "\W", "-").ToLowerInvariant())).
+See release notes [here](https://github.com/microsoft/testfx-docs/blob/main/docs/releases.md#$(("$v $date" -replace "\.", "" -replace "\W", "-").ToLowerInvariant())).
---
diff --git a/src/Adapter/Build/Desktop/MSTest.TestAdapter.targets b/src/Adapter/Build/Desktop/MSTest.TestAdapter.targets
index 0649e3a2a..1c80426d0 100644
--- a/src/Adapter/Build/Desktop/MSTest.TestAdapter.targets
+++ b/src/Adapter/Build/Desktop/MSTest.TestAdapter.targets
@@ -1,7 +1,7 @@
- true
+ true
@@ -10,21 +10,21 @@
So the below code should not break build in any case. -->
-
-
-
-
+
+
+
+
-
+
%(CurrentUICultureHierarchy.Identity)
-
+
%(MSTestV2ResourceFiles.CultureString)\%(Filename)%(Extension)
PreserveNewest
False
diff --git a/src/Adapter/Build/Universal/MSTest.TestAdapter.targets b/src/Adapter/Build/Universal/MSTest.TestAdapter.targets
index b0404380c..8d11b4937 100644
--- a/src/Adapter/Build/Universal/MSTest.TestAdapter.targets
+++ b/src/Adapter/Build/Universal/MSTest.TestAdapter.targets
@@ -1,7 +1,7 @@
- true
+ true
@@ -10,15 +10,15 @@
So the below code should not break build in any case. -->
-
-
-
-
+
+
+
+
-
+
%(CurrentUICultureHierarchy.Identity)
diff --git a/src/Adapter/Build/WinUI/MSTest.TestAdapter.props b/src/Adapter/Build/WinUI/MSTest.TestAdapter.props
new file mode 100644
index 000000000..aa6baccb4
--- /dev/null
+++ b/src/Adapter/Build/WinUI/MSTest.TestAdapter.props
@@ -0,0 +1,33 @@
+
+
+
+
+ Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.dll
+ PreserveNewest
+ False
+
+
+ Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface.dll
+ PreserveNewest
+ False
+
+
+ Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.dll
+ PreserveNewest
+ False
+
+
+ Microsoft.TestPlatform.AdapterUtilities.dll
+ PreserveNewest
+ False
+
+
+
+
+
+
+
+
diff --git a/src/Adapter/Build/WinUI/MSTest.TestAdapter.targets b/src/Adapter/Build/WinUI/MSTest.TestAdapter.targets
new file mode 100644
index 000000000..8d11b4937
--- /dev/null
+++ b/src/Adapter/Build/WinUI/MSTest.TestAdapter.targets
@@ -0,0 +1,42 @@
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ %(CurrentUICultureHierarchy.Identity)
+
+
+
+
+
+
+
+
+ $(CurrentUICultureHierarchy)\%(FileName).resources.dll
+ PreserveNewest
+ %(FullPath)
+ False
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Adapter/MSTest.CoreAdapter/Constants.cs b/src/Adapter/MSTest.CoreAdapter/Constants.cs
index 98a758d91..6d930643a 100644
--- a/src/Adapter/MSTest.CoreAdapter/Constants.cs
+++ b/src/Adapter/MSTest.CoreAdapter/Constants.cs
@@ -89,6 +89,9 @@ internal static class Constants
internal static readonly TestProperty TfsTeamProjectProperty = TestProperty.Register(TfsTeamProject, TfsTeamProject, typeof(string), TestPropertyAttributes.Hidden, typeof(TestCase));
+ internal static readonly TestProperty TestDynamicDataTypeProperty = TestProperty.Register("MSTest.DynamicDataType", "DynamicDataType", typeof(int), TestPropertyAttributes.Hidden, typeof(TestCase));
+
+ internal static readonly TestProperty TestDynamicDataProperty = TestProperty.Register("MSTest.DynamicData", "DynamicData", typeof(string[]), TestPropertyAttributes.Hidden, typeof(TestCase));
#endregion
#region Private Constants
diff --git a/src/Adapter/MSTest.CoreAdapter/Discovery/AssemblyEnumerator.cs b/src/Adapter/MSTest.CoreAdapter/Discovery/AssemblyEnumerator.cs
index 4c67d2bad..a8a3b9dde 100644
--- a/src/Adapter/MSTest.CoreAdapter/Discovery/AssemblyEnumerator.cs
+++ b/src/Adapter/MSTest.CoreAdapter/Discovery/AssemblyEnumerator.cs
@@ -6,21 +6,35 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Discovery
using System;
using System.Collections.Generic;
using System.Diagnostics;
- using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using System.Reflection;
+ using System.Runtime.Serialization;
using System.Security;
using System.Text;
+ using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution;
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers;
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel;
+ using Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices.Interface;
+
+ using UTF = Microsoft.VisualStudio.TestTools.UnitTesting;
///
/// Enumerates through all types in the assembly in search of valid test methods.
///
internal class AssemblyEnumerator : MarshalByRefObject
{
+ ///
+ /// Helper for reflection API's.
+ ///
+ private static readonly ReflectHelper ReflectHelper = ReflectHelper.Instance;
+
+ ///
+ /// Type cache
+ ///
+ private readonly TypeCache typeCache = new TypeCache(ReflectHelper);
+
///
/// Initializes a new instance of the class.
///
@@ -40,6 +54,11 @@ public AssemblyEnumerator(MSTestSettings settings)
MSTestSettings.PopulateSettings(settings);
}
+ ///
+ /// Gets or sets the run settings to use for current discovery session.
+ ///
+ public string RunSettingsXml { get; set; }
+
///
/// Returns object to be used for controlling lifetime, null means infinite lifetime.
///
@@ -62,6 +81,7 @@ internal ICollection EnumerateAssembly(string assemblyFileName,
{
Debug.Assert(!string.IsNullOrWhiteSpace(assemblyFileName), "Invalid assembly file name.");
+ var runSettingsXml = this.RunSettingsXml;
var warningMessages = new List();
var tests = new List();
@@ -88,42 +108,8 @@ internal ICollection EnumerateAssembly(string assemblyFileName,
continue;
}
- string typeFullName = null;
-
- try
- {
- ICollection warningsFromTypeEnumerator;
-
- typeFullName = type.FullName;
- var unitTestCases = this.GetTypeEnumerator(type, assemblyFileName).Enumerate(out warningsFromTypeEnumerator);
-
- if (warningsFromTypeEnumerator != null)
- {
- warningMessages.AddRange(warningsFromTypeEnumerator);
- }
-
- if (unitTestCases != null)
- {
- tests.AddRange(unitTestCases);
- }
- }
- catch (Exception exception)
- {
- // If we fail to discover type from a class, then don't abort the discovery
- // Move to the next type.
- string message = string.Format(
- CultureInfo.CurrentCulture,
- Resource.CouldNotInspectTypeDuringDiscovery,
- typeFullName,
- assemblyFileName,
- exception.Message);
- warningMessages.Add(message);
-
- PlatformServiceProvider.Instance.AdapterTraceLogger.LogInfo(
- "AssemblyEnumerator: Exception occurred while enumerating type {0}. {1}",
- typeFullName,
- exception);
- }
+ var testsInType = this.DiscoverTestsInType(assemblyFileName, runSettingsXml, assembly, type, warningMessages);
+ tests.AddRange(testsInType);
}
warnings = warningMessages;
@@ -146,20 +132,13 @@ internal Type[] GetTypes(Assembly assembly, string assemblyFileName, ICollection
}
catch (ReflectionTypeLoadException ex)
{
- PlatformServiceProvider.Instance.AdapterTraceLogger.LogWarning(
- "MSTestExecutor.TryGetTests: Failed to discover tests from {0}. Reason:{1}",
- assemblyFileName,
- ex);
- PlatformServiceProvider.Instance.AdapterTraceLogger.LogWarning("Exceptions thrown from the Loader :");
+ PlatformServiceProvider.Instance.AdapterTraceLogger.LogWarning($"MSTestExecutor.TryGetTests: {Resource.TestAssembly_AssemblyDiscoveryFailure}", assemblyFileName, ex);
+ PlatformServiceProvider.Instance.AdapterTraceLogger.LogWarning(Resource.ExceptionsThrown);
if (ex.LoaderExceptions != null)
{
// If not able to load all type, log a warning and continue with loaded types.
- var message = string.Format(
- CultureInfo.CurrentCulture,
- Resource.TypeLoadFailed,
- assemblyFileName,
- this.GetLoadExceptionDetails(ex));
+ var message = string.Format(CultureInfo.CurrentCulture, Resource.TypeLoadFailed, assemblyFileName, this.GetLoadExceptionDetails(ex));
warningMessages?.Add(message);
@@ -217,11 +196,205 @@ internal string GetLoadExceptionDetails(ReflectionTypeLoadException ex)
/// a TypeEnumerator instance.
internal virtual TypeEnumerator GetTypeEnumerator(Type type, string assemblyFileName)
{
- var reflectHelper = new ReflectHelper();
- var typevalidator = new TypeValidator(reflectHelper);
- var testMethodValidator = new TestMethodValidator(reflectHelper);
+ var typeValidator = new TypeValidator(ReflectHelper);
+ var testMethodValidator = new TestMethodValidator(ReflectHelper);
+
+ return new TypeEnumerator(type, assemblyFileName, ReflectHelper, typeValidator, testMethodValidator);
+ }
+
+ private IEnumerable DiscoverTestsInType(string assemblyFileName, string runSettingsXml, Assembly assembly, Type type, List warningMessages)
+ {
+ var sourceLevelParameters = PlatformServiceProvider.Instance.SettingsProvider.GetProperties(assemblyFileName);
+ sourceLevelParameters = RunSettingsUtilities.GetTestRunParameters(runSettingsXml)?.ConcatWithOverwrites(sourceLevelParameters)
+ ?? sourceLevelParameters
+ ?? new Dictionary();
+
+ string typeFullName = null;
+ var tests = new List();
+
+ try
+ {
+ typeFullName = type.FullName;
+ var unitTestCases = this.GetTypeEnumerator(type, assemblyFileName).Enumerate(out var warningsFromTypeEnumerator);
+ var typeIgnored = ReflectHelper.IsAttributeDefined(type, typeof(UTF.IgnoreAttribute), false);
+
+ if (warningsFromTypeEnumerator != null)
+ {
+ warningMessages.AddRange(warningsFromTypeEnumerator);
+ }
+
+ if (unitTestCases != null)
+ {
+ foreach (var test in unitTestCases)
+ {
+ if (this.DynamicDataAttached(sourceLevelParameters, assembly, test, tests))
+ {
+ continue;
+ }
+
+ tests.Add(test);
+ }
+ }
+ }
+ catch (Exception exception)
+ {
+ // If we fail to discover type from a class, then don't abort the discovery
+ // Move to the next type.
+ string message = string.Format(CultureInfo.CurrentCulture, Resource.CouldNotInspectTypeDuringDiscovery, typeFullName, assemblyFileName, exception.Message);
+ PlatformServiceProvider.Instance.AdapterTraceLogger.LogInfo($"AssemblyEnumerator: {message}");
+ warningMessages.Add(message);
+ }
+
+ return tests;
+ }
+
+ private bool DynamicDataAttached(IDictionary sourceLevelParameters, Assembly assembly, UnitTestElement test, List tests)
+ {
+ // It should always be `true`, but if any part of the chain is obsolete; it might not contain those.
+ // Since we depend on those properties, if they don't exist, we bail out early.
+ if (!test.TestMethod.HasManagedMethodAndTypeProperties)
+ {
+ return false;
+ }
+
+ using (var writer = new ThreadSafeStringWriter(CultureInfo.InvariantCulture))
+ {
+ var testMethod = test.TestMethod;
+ var testContext = PlatformServiceProvider.Instance.GetTestContext(testMethod, writer, sourceLevelParameters);
+ var testMethodInfo = this.typeCache.GetTestMethodInfo(testMethod, testContext, MSTestSettings.CurrentSettings.CaptureDebugTraces);
+ if (testMethodInfo == null)
+ {
+ return false;
+ }
+
+ return /* DataSourceAttribute discovery is disabled for now, since we cannot serialize DataRow values.
+ this.TryProcessDataSource(test, testMethodInfo, testContext, tests) || */
+ this.TryProcessTestDataSourceTests(test, testMethodInfo, tests);
+ }
+ }
+
+ private bool TryProcessDataSource(UnitTestElement test, TestMethodInfo testMethodInfo, ITestContext testContext, List tests)
+ {
+ var dataSourceAttributes = ReflectHelper.GetAttributes(testMethodInfo.MethodInfo, false);
+ if (dataSourceAttributes == null)
+ {
+ return false;
+ }
+
+ if (dataSourceAttributes.Length > 1)
+ {
+ var message = string.Format(CultureInfo.CurrentCulture, Resource.CannotEnumerateDataSourceAttribute_MoreThenOneDefined, test.TestMethod.ManagedTypeName, test.TestMethod.ManagedMethodName, dataSourceAttributes.Length);
+ PlatformServiceProvider.Instance.AdapterTraceLogger.LogInfo($"DynamicDataEnumarator: {message}");
+ throw new InvalidOperationException(message);
+ }
+
+ // dataSourceAttributes.Length == 1
+ try
+ {
+ return this.ProcessDataSourceTests(test, testMethodInfo, testContext, tests);
+ }
+ catch (Exception ex)
+ {
+ var message = string.Format(CultureInfo.CurrentCulture, Resource.CannotEnumerateDataSourceAttribute, test.TestMethod.ManagedTypeName, test.TestMethod.ManagedMethodName, ex);
+ PlatformServiceProvider.Instance.AdapterTraceLogger.LogInfo($"DynamicDataEnumarator: {message}");
+ return false;
+ }
+ }
+
+ private bool ProcessDataSourceTests(UnitTestElement test, TestMethodInfo testMethodInfo, ITestContext testContext, List tests)
+ {
+ var dataRows = PlatformServiceProvider.Instance.TestDataSource.GetData(testMethodInfo, testContext);
+ if (dataRows == null || !dataRows.Any())
+ {
+ return false;
+ }
+
+ try
+ {
+ int rowIndex = 0;
+
+ foreach (var dataRow in dataRows)
+ {
+ // TODO: Test serialization
+ rowIndex++;
+
+ var displayName = string.Format(CultureInfo.CurrentCulture, Resource.DataDrivenResultDisplayName, test.DisplayName, rowIndex);
+ var discoveredTest = test.Clone();
+ discoveredTest.DisplayName = displayName;
+ discoveredTest.TestMethod.DataType = DynamicDataType.DataSourceAttribute;
+ discoveredTest.TestMethod.SerializedData = DataSerializationHelper.Serialize(new[] { (object)rowIndex });
+ tests.Add(discoveredTest);
+ }
+
+ return true;
+ }
+ finally
+ {
+ testContext.SetDataConnection(null);
+ testContext.SetDataRow(null);
+ }
+ }
+
+ private bool TryProcessTestDataSourceTests(UnitTestElement test, TestMethodInfo testMethodInfo, List tests)
+ {
+ var methodInfo = testMethodInfo.MethodInfo;
+ var testDataSources = ReflectHelper.GetAttributes(methodInfo, false)?.Where(a => a is UTF.ITestDataSource).OfType().ToArray();
+ if (testDataSources == null || testDataSources.Length == 0)
+ {
+ return false;
+ }
+
+ try
+ {
+ return this.ProcessTestDataSourceTests(test, (MethodInfo)methodInfo, testDataSources, tests);
+ }
+ catch (Exception ex)
+ {
+ var message = string.Format(CultureInfo.CurrentCulture, Resource.CannotEnumerateIDataSourceAttribute, test.TestMethod.ManagedTypeName, test.TestMethod.ManagedMethodName, ex);
+ PlatformServiceProvider.Instance.AdapterTraceLogger.LogInfo($"DynamicDataEnumarator: {message}");
+ return false;
+ }
+ }
+
+ private bool ProcessTestDataSourceTests(UnitTestElement test, MethodInfo methodInfo, UTF.ITestDataSource[] testDataSources, List tests)
+ {
+ foreach (var dataSource in testDataSources)
+ {
+ var data = dataSource.GetData(methodInfo);
+ var discoveredTests = new List();
+ var serializationFailed = false;
+
+ foreach (var d in data)
+ {
+ var discoveredTest = test.Clone();
+ discoveredTest.DisplayName = dataSource.GetDisplayName(methodInfo, d);
+
+ try
+ {
+ discoveredTest.TestMethod.SerializedData = DataSerializationHelper.Serialize(d);
+ discoveredTest.TestMethod.DataType = DynamicDataType.ITestDataSource;
+ }
+ catch (SerializationException)
+ {
+ serializationFailed = true;
+ break;
+ }
+
+ discoveredTests.Add(discoveredTest);
+ }
+
+ // Serialization failed for the type, bail out.
+ if (serializationFailed)
+ {
+ tests.Add(test);
+
+ break;
+ }
+
+ tests.AddRange(discoveredTests);
+ }
- return new TypeEnumerator(type, assemblyFileName, reflectHelper, typevalidator, testMethodValidator);
+ return true;
}
}
}
diff --git a/src/Adapter/MSTest.CoreAdapter/Discovery/AssemblyEnumeratorWrapper.cs b/src/Adapter/MSTest.CoreAdapter/Discovery/AssemblyEnumeratorWrapper.cs
index 2a1d19244..42f2a7a76 100644
--- a/src/Adapter/MSTest.CoreAdapter/Discovery/AssemblyEnumeratorWrapper.cs
+++ b/src/Adapter/MSTest.CoreAdapter/Discovery/AssemblyEnumeratorWrapper.cs
@@ -69,7 +69,7 @@ internal ICollection GetTests(string assemblyFileName, IRunSett
{
var message = string.Format(CultureInfo.CurrentCulture, Resource.TestAssembly_AssemblyDiscoveryFailure, fullFilePath, ex.Message);
PlatformServiceProvider.Instance.AdapterTraceLogger.LogWarning($"{nameof(AssemblyEnumeratorWrapper)}.{nameof(this.GetTests)}: {Resource.TestAssembly_AssemblyDiscoveryFailure}", fullFilePath, ex);
- PlatformServiceProvider.Instance.AdapterTraceLogger.LogWarning("Exceptions thrown from the loader: ");
+ PlatformServiceProvider.Instance.AdapterTraceLogger.LogWarning(Resource.ExceptionsThrown);
warnings.Add(message);
if (ex.LoaderExceptions != null)
@@ -108,6 +108,16 @@ private ICollection GetTestsInIsolation(string fullFilePath, IR
// Create an instance of a type defined in adapter so that adapter gets loaded in the child app domain
var assemblyEnumerator = isolationHost.CreateInstanceForType(typeof(AssemblyEnumerator), new object[] { MSTestSettings.CurrentSettings }) as AssemblyEnumerator;
+ // This might not be supported if an older version of "PlatformServices" (Microsoft.VisualStudio.TestPlatform.MSTestAdapter.PlatformServices) assembly is already loaded into the App Domain.
+ try
+ {
+ assemblyEnumerator.RunSettingsXml = runSettings?.SettingsXml;
+ }
+ catch
+ {
+ PlatformServiceProvider.Instance.AdapterTraceLogger.LogWarning(Resource.OlderTFMVersionFound);
+ }
+
return assemblyEnumerator.EnumerateAssembly(fullFilePath, out warnings);
}
}
diff --git a/src/Adapter/MSTest.CoreAdapter/Discovery/TypeEnumerator.cs b/src/Adapter/MSTest.CoreAdapter/Discovery/TypeEnumerator.cs
index 5c585a579..769545484 100644
--- a/src/Adapter/MSTest.CoreAdapter/Discovery/TypeEnumerator.cs
+++ b/src/Adapter/MSTest.CoreAdapter/Discovery/TypeEnumerator.cs
@@ -198,11 +198,10 @@ internal UnitTestElement GetTestFromMethod(MethodInfo method, bool isDeclaredInT
testElement.WorkItemIds = workItemAttributes.Select(x => x.Id.ToString()).ToArray();
}
+ testElement.Ignored = this.reflectHelper.IsAttributeDefined(method, typeof(IgnoreAttribute), false);
+
// Get Deployment items if any.
- testElement.DeploymentItems = PlatformServiceProvider.Instance.TestDeployment.GetDeploymentItems(
- method,
- this.type,
- warnings);
+ testElement.DeploymentItems = PlatformServiceProvider.Instance.TestDeployment.GetDeploymentItems(method, this.type, warnings);
// get DisplayName from TestMethodAttribute
var testMethodAttribute = this.reflectHelper.GetCustomAttribute(method, typeof(TestMethodAttribute)) as TestMethodAttribute;
diff --git a/src/Adapter/MSTest.CoreAdapter/Discovery/UnitTestDiscoverer.cs b/src/Adapter/MSTest.CoreAdapter/Discovery/UnitTestDiscoverer.cs
index 4a75207da..dbd6614bb 100644
--- a/src/Adapter/MSTest.CoreAdapter/Discovery/UnitTestDiscoverer.cs
+++ b/src/Adapter/MSTest.CoreAdapter/Discovery/UnitTestDiscoverer.cs
@@ -58,9 +58,7 @@ internal UnitTestDiscoverer()
ITestCaseDiscoverySink discoverySink,
IDiscoveryContext discoveryContext)
{
- ICollection warnings;
-
- var testElements = this.assemblyEnumeratorWrapper.GetTests(source, discoveryContext?.RunSettings, out warnings);
+ var testElements = this.assemblyEnumeratorWrapper.GetTests(source, discoveryContext?.RunSettings, out var warnings);
// log the warnings
foreach (var warning in warnings)
@@ -100,8 +98,7 @@ internal void SendTestCases(string source, IEnumerable testElem
}
// Get filter expression and skip discovery in case filter expression has parsing error.
- bool filterHasError = false;
- ITestCaseFilterExpression filterExpression = this.TestMethodFilter.GetFilterExpression(discoveryContext, logger, out filterHasError);
+ ITestCaseFilterExpression filterExpression = this.TestMethodFilter.GetFilterExpression(discoveryContext, logger, out var filterHasError);
if (filterHasError)
{
return;
@@ -117,12 +114,11 @@ internal void SendTestCases(string source, IEnumerable testElem
continue;
}
- object testNavigationSession;
if (shouldCollectSourceInformation)
{
string testSource = testElement.TestMethod.DeclaringAssemblyName ?? source;
- if (!navigationSessions.TryGetValue(testSource, out testNavigationSession))
+ if (!navigationSessions.TryGetValue(testSource, out var testNavigationSession))
{
testNavigationSession = PlatformServiceProvider.Instance.FileOperations.CreateNavigationSession(testSource);
navigationSessions.Add(testSource, testNavigationSession);
@@ -144,15 +140,12 @@ internal void SendTestCases(string source, IEnumerable testElem
methodName = "MoveNext";
}
- int minLineNumber;
- string fileName;
-
PlatformServiceProvider.Instance.FileOperations.GetNavigationData(
testNavigationSession,
className,
methodName,
- out minLineNumber,
- out fileName);
+ out var minLineNumber,
+ out var fileName);
if (!string.IsNullOrEmpty(fileName))
{
diff --git a/src/Adapter/MSTest.CoreAdapter/Execution/StackTraceHelper.cs b/src/Adapter/MSTest.CoreAdapter/Execution/StackTraceHelper.cs
index 6b7fded5e..d9cd04721 100644
--- a/src/Adapter/MSTest.CoreAdapter/Execution/StackTraceHelper.cs
+++ b/src/Adapter/MSTest.CoreAdapter/Execution/StackTraceHelper.cs
@@ -97,13 +97,12 @@ internal static StackTraceInformation GetStackTraceInformation(Exception ex)
bool first = true;
while (stackTraces.Count != 0)
{
- result.Append(
- string.Format(
+ result.AppendFormat(
CultureInfo.CurrentCulture,
"{0} {1}{2}",
first ? string.Empty : (Resource.UTA_EndOfInnerExceptionTrace + Environment.NewLine),
stackTraces.Pop(),
- Environment.NewLine));
+ Environment.NewLine);
first = false;
}
@@ -121,7 +120,7 @@ internal static StackTraceInformation GetStackTraceInformation(Exception ex)
///
internal static string TrimStackTrace(string stackTrace)
{
- Debug.Assert(stackTrace != null && stackTrace.Length > 0, "stack trace should be non-empty.");
+ Debug.Assert(!string.IsNullOrEmpty(stackTrace), "stack trace should be non-empty.");
StringBuilder result = new StringBuilder(stackTrace.Length);
string[] stackFrames = Regex.Split(stackTrace, Environment.NewLine);
@@ -179,13 +178,12 @@ internal static string GetExceptionMessage(Exception ex)
msg = string.Format(CultureInfo.CurrentCulture, Resource.UTF_FailedToGetExceptionMessage, curException.GetType());
}
- result.Append(
- string.Format(
+ result.AppendFormat(
CultureInfo.CurrentCulture,
"{0}{1}: {2}",
first ? string.Empty : " ---> ",
curException.GetType(),
- msg));
+ msg);
first = false;
}
diff --git a/src/Adapter/MSTest.CoreAdapter/Execution/TestAssemblyInfo.cs b/src/Adapter/MSTest.CoreAdapter/Execution/TestAssemblyInfo.cs
index b197afcda..ca3ff03b9 100644
--- a/src/Adapter/MSTest.CoreAdapter/Execution/TestAssemblyInfo.cs
+++ b/src/Adapter/MSTest.CoreAdapter/Execution/TestAssemblyInfo.cs
@@ -173,9 +173,7 @@ public void RunAssemblyInitialize(TestContext testContext)
?? this.AssemblyInitializationException;
var outcome = UnitTestOutcome.Failed;
- string errorMessage = null;
- StackTraceInformation stackTraceInfo = null;
- if (!realException.TryGetUnitTestAssertException(out outcome, out errorMessage, out stackTraceInfo))
+ if (!realException.TryGetUnitTestAssertException(out outcome, out var errorMessage, out var stackTraceInfo))
{
var exception = realException.GetType().ToString();
var message = StackTraceHelper.GetExceptionMessage(realException);
diff --git a/src/Adapter/MSTest.CoreAdapter/Execution/TestAssemblySettingsProvider.cs b/src/Adapter/MSTest.CoreAdapter/Execution/TestAssemblySettingsProvider.cs
index a5d904d53..b21eca5b2 100644
--- a/src/Adapter/MSTest.CoreAdapter/Execution/TestAssemblySettingsProvider.cs
+++ b/src/Adapter/MSTest.CoreAdapter/Execution/TestAssemblySettingsProvider.cs
@@ -5,6 +5,7 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution
{
using System;
using System.Security;
+
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers;
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel;
@@ -13,7 +14,7 @@ internal class TestAssemblySettingsProvider : MarshalByRefObject
private ReflectHelper reflectHelper;
public TestAssemblySettingsProvider()
- : this(new ReflectHelper())
+ : this(ReflectHelper.Instance)
{
}
diff --git a/src/Adapter/MSTest.CoreAdapter/Execution/TestExecutionManager.cs b/src/Adapter/MSTest.CoreAdapter/Execution/TestExecutionManager.cs
index ba61d7b71..dc95db608 100644
--- a/src/Adapter/MSTest.CoreAdapter/Execution/TestExecutionManager.cs
+++ b/src/Adapter/MSTest.CoreAdapter/Execution/TestExecutionManager.cs
@@ -13,6 +13,7 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Extensions;
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers;
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel;
@@ -375,18 +376,14 @@ private void ExecuteTestsInSource(IEnumerable tests, IRunContext runCo
var startTime = DateTimeOffset.Now;
- PlatformServiceProvider.Instance.AdapterTraceLogger.LogInfo(
- "Executing test {0}",
- unitTestElement.TestMethod.Name);
+ PlatformServiceProvider.Instance.AdapterTraceLogger.LogInfo("Executing test {0}", unitTestElement.TestMethod.Name);
// Run single test passing test context properties to it.
var tcmProperties = TcmTestPropertiesProvider.GetTcmProperties(currentTest);
var testContextProperties = this.GetTestContextProperties(tcmProperties, sourceLevelParameters);
var unitTestResult = testRunner.RunSingleTest(unitTestElement.TestMethod, testContextProperties);
- PlatformServiceProvider.Instance.AdapterTraceLogger.LogInfo(
- "Executed test {0}",
- unitTestElement.TestMethod.Name);
+ PlatformServiceProvider.Instance.AdapterTraceLogger.LogInfo("Executed test {0}", unitTestElement.TestMethod.Name);
var endTime = DateTimeOffset.Now;
@@ -472,17 +469,17 @@ private void LogCleanupResult(ITestExecutionRecorder testExecutionRecorder, RunC
{
Debug.Assert(testExecutionRecorder != null, "Logger should not be null");
- if (!string.IsNullOrEmpty(result.StandardOut))
+ if (!string.IsNullOrWhiteSpace(result.StandardOut))
{
testExecutionRecorder.SendMessage(TestMessageLevel.Informational, result.StandardOut);
}
- if (!string.IsNullOrEmpty(result.DebugTrace))
+ if (!string.IsNullOrWhiteSpace(result.DebugTrace))
{
testExecutionRecorder.SendMessage(TestMessageLevel.Informational, result.DebugTrace);
}
- if (!string.IsNullOrEmpty(result.StandardError))
+ if (!string.IsNullOrWhiteSpace(result.StandardError))
{
testExecutionRecorder.SendMessage(
MSTestSettings.CurrentSettings.TreatClassAndAssemblyCleanupWarningsAsErrors ? TestMessageLevel.Error : TestMessageLevel.Warning,
@@ -493,9 +490,12 @@ private void LogCleanupResult(ITestExecutionRecorder testExecutionRecorder, RunC
{
foreach (string warning in result.Warnings)
{
- testExecutionRecorder.SendMessage(
- MSTestSettings.CurrentSettings.TreatClassAndAssemblyCleanupWarningsAsErrors ? TestMessageLevel.Error : TestMessageLevel.Warning,
- warning);
+ if (!string.IsNullOrWhiteSpace(warning))
+ {
+ testExecutionRecorder.SendMessage(
+ MSTestSettings.CurrentSettings.TreatClassAndAssemblyCleanupWarningsAsErrors ? TestMessageLevel.Error : TestMessageLevel.Warning,
+ warning);
+ }
}
}
}
diff --git a/src/Adapter/MSTest.CoreAdapter/Execution/TestMethodInfo.cs b/src/Adapter/MSTest.CoreAdapter/Execution/TestMethodInfo.cs
index fd918bd17..1d4d0d13b 100644
--- a/src/Adapter/MSTest.CoreAdapter/Execution/TestMethodInfo.cs
+++ b/src/Adapter/MSTest.CoreAdapter/Execution/TestMethodInfo.cs
@@ -11,10 +11,12 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Execution
using System.Reflection;
using System.Text;
using System.Threading;
+
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Extensions;
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers;
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel;
using Microsoft.VisualStudio.TestTools.UnitTesting;
+
using UnitTestOutcome = Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel.UnitTestOutcome;
using UTF = Microsoft.VisualStudio.TestTools.UnitTesting;
@@ -92,30 +94,8 @@ public Attribute[] GetAllAttributes(bool inherit)
public TAttributeType[] GetAttributes(bool inherit)
where TAttributeType : Attribute
- {
- Attribute[] attributeArray = ReflectHelper.GetCustomAttributes(this.TestMethod, typeof(TAttributeType), inherit);
-
- TAttributeType[] tAttributeArray = attributeArray as TAttributeType[];
- if (tAttributeArray != null)
- {
- return tAttributeArray;
- }
-
- List tAttributeList = new List();
- if (attributeArray != null)
- {
- foreach (Attribute attribute in attributeArray)
- {
- TAttributeType tAttribute = attribute as TAttributeType;
- if (tAttribute != null)
- {
- tAttributeList.Add(tAttribute);
- }
- }
- }
-
- return tAttributeList.ToArray();
- }
+ => ReflectHelper.GetAttributes(this.TestMethod, inherit)
+ ?? EmptyHolder.Array;
///
/// Execute test method. Capture failures, handle async and return result.
@@ -453,11 +433,9 @@ private Exception HandleMethodException(Exception ex, string className, string m
// Get the real exception thrown by the test method
Exception realException = this.GetRealException(ex);
- string exceptionMessage = null;
- StackTraceInformation exceptionStackTraceInfo = null;
var outcome = TestTools.UnitTesting.UnitTestOutcome.Failed;
- if (realException.TryGetUnitTestAssertException(out outcome, out exceptionMessage, out exceptionStackTraceInfo))
+ if (realException.TryGetUnitTestAssertException(out outcome, out var exceptionMessage, out var exceptionStackTraceInfo))
{
return new TestFailedException(outcome.ToUnitTestOutcome(), exceptionMessage, exceptionStackTraceInfo, realException);
}
@@ -546,11 +524,9 @@ private void RunTestCleanupMethod(object classInstance, TestResult result)
}
Exception realException = ex.GetInnerExceptionOrDefault();
- string exceptionMessage = null;
- StackTraceInformation realExceptionStackTraceInfo = null;
// special case UnitTestAssertException to trim off part of the stack trace
- if (!realException.TryGetUnitTestAssertException(out cleanupOutcome, out exceptionMessage, out realExceptionStackTraceInfo))
+ if (!realException.TryGetUnitTestAssertException(out cleanupOutcome, out var exceptionMessage, out var realExceptionStackTraceInfo))
{
cleanupOutcome = UTF.UnitTestOutcome.Failed;
exceptionMessage = this.GetTestCleanUpExceptionMessage(testCleanupMethod, realException);
@@ -632,11 +608,9 @@ private bool RunTestInitializeMethod(object classInstance, TestResult result)
catch (Exception ex)
{
var innerException = ex.GetInnerExceptionOrDefault();
- string exceptionMessage = null;
- StackTraceInformation exceptionStackTraceInfo = null;
var outcome = TestTools.UnitTesting.UnitTestOutcome.Failed;
- if (innerException.TryGetUnitTestAssertException(out outcome, out exceptionMessage, out exceptionStackTraceInfo))
+ if (innerException.TryGetUnitTestAssertException(out outcome, out var exceptionMessage, out var exceptionStackTraceInfo))
{
result.Outcome = outcome;
result.TestFailureException = new TestFailedException(
@@ -725,11 +699,27 @@ private object CreateTestClassInstance(TestResult result)
}
catch (Exception ex)
{
+ if (ex == null)
+ {
+ // It seems that ex can be null in some rare cases when initialization fails in native code.
+ // Get our own exception with a stack trace to satisfy GetStackTraceInformation.
+ try
+ {
+ throw new InvalidOperationException(Resource.UTA_UserCodeThrewNullValueException);
+ }
+ catch (Exception exception)
+ {
+ ex = exception;
+ }
+ }
+
// In most cases, exception will be TargetInvocationException with real exception wrapped
- // in the InnerException; or user code throws an exception
+ // in the InnerException; or user code throws an exception.
+ // It also seems that in rare cases the ex can be null.
var actualException = ex.InnerException ?? ex;
var exceptionMessage = StackTraceHelper.GetExceptionMessage(actualException);
var stackTraceInfo = StackTraceHelper.GetStackTraceInformation(actualException);
+
var errorMessage = string.Format(
CultureInfo.CurrentCulture,
Resource.UTA_InstanceCreationError,
@@ -796,5 +786,10 @@ void executeAsyncAction()
return timeoutResult;
}
}
+
+ private static class EmptyHolder
+ {
+ internal static readonly T[] Array = new T[0];
+ }
}
}
diff --git a/src/Adapter/MSTest.CoreAdapter/Execution/TestMethodRunner.cs b/src/Adapter/MSTest.CoreAdapter/Execution/TestMethodRunner.cs
index 63bc78323..8dfd82a85 100644
--- a/src/Adapter/MSTest.CoreAdapter/Execution/TestMethodRunner.cs
+++ b/src/Adapter/MSTest.CoreAdapter/Execution/TestMethodRunner.cs
@@ -64,21 +64,9 @@ internal class TestMethodRunner
///
/// The capture debug traces.
///
- public TestMethodRunner(
- TestMethodInfo testMethodInfo,
- TestMethod testMethod,
- ITestContext testContext,
- bool captureDebugTraces)
- : this(testMethodInfo, testMethod, testContext, captureDebugTraces, new ReflectHelper())
+ public TestMethodRunner(TestMethodInfo testMethodInfo, TestMethod testMethod, ITestContext testContext, bool captureDebugTraces)
+ : this(testMethodInfo, testMethod, testContext, captureDebugTraces, ReflectHelper.Instance)
{
- Debug.Assert(testMethodInfo != null, "testMethodInfo should not be null");
- Debug.Assert(testMethod != null, "testMethod should not be null");
- Debug.Assert(testContext != null, "testContext should not be null");
-
- this.testMethodInfo = testMethodInfo;
- this.test = testMethod;
- this.testContext = testContext;
- this.captureDebugTraces = captureDebugTraces;
}
///
@@ -99,12 +87,7 @@ internal class TestMethodRunner
///
/// The reflect Helper object.
///
- public TestMethodRunner(
- TestMethodInfo testMethodInfo,
- TestMethod testMethod,
- ITestContext testContext,
- bool captureDebugTraces,
- ReflectHelper reflectHelper)
+ public TestMethodRunner(TestMethodInfo testMethodInfo, TestMethod testMethod, ITestContext testContext, bool captureDebugTraces, ReflectHelper reflectHelper)
{
Debug.Assert(testMethodInfo != null, "testMethodInfo should not be null");
Debug.Assert(testMethod != null, "testMethod should not be null");
@@ -219,136 +202,31 @@ internal UnitTestResult[] RunTestMethod()
List results = new List();
var isDataDriven = false;
- // Parent result. Added in properties bag only when results are greater than 1.
- var parentResultWatch = new Stopwatch();
- parentResultWatch.Start();
- var parentResult = new UTF.TestResult
- {
- Outcome = UTF.UnitTestOutcome.InProgress,
- ExecutionId = Guid.NewGuid()
- };
-
if (this.testMethodInfo.TestMethodOptions.Executor != null)
{
- UTF.DataSourceAttribute[] dataSourceAttribute = this.testMethodInfo.GetAttributes(false);
- if (dataSourceAttribute != null && dataSourceAttribute.Length == 1)
+ if (this.test.DataType == DynamicDataType.ITestDataSource)
+ {
+ var data = DataSerializationHelper.Deserialize(this.test.SerializedData);
+ var testResults = this.ExecuteTestWithDataSource(null, data);
+ results.AddRange(testResults);
+ }
+ else if (this.ExecuteDataSourceBasedTests(results))
{
isDataDriven = true;
- Stopwatch watch = new Stopwatch();
- watch.Start();
-
- try
- {
- IEnumerable
/// Results.
- /// Parent results.
+ /// Current execution id.
/// Updated results which contains parent result as first result. All other results contains parent result info.
- private List UpdateResultsWithParentInfo(List results, UTF.TestResult parentResult)
+ private List UpdateResultsWithParentInfo(List results, Guid executionId)
{
// Return results in case there are no results.
if (!results.Any())
@@ -422,13 +455,11 @@ private List UpdateResultsWithParentInfo(List re
// UpdatedResults contain parent result at first position and remaining results has parent info updated.
var updatedResults = new List();
- updatedResults.Add(parentResult);
foreach (var result in results)
{
result.ExecutionId = Guid.NewGuid();
- result.ParentExecId = parentResult.ExecutionId;
- parentResult.InnerResultsCount++;
+ result.ParentExecId = executionId;
updatedResults.Add(result);
}
diff --git a/src/Adapter/MSTest.CoreAdapter/Execution/TypeCache.cs b/src/Adapter/MSTest.CoreAdapter/Execution/TypeCache.cs
index 074845f5f..058f1a057 100644
--- a/src/Adapter/MSTest.CoreAdapter/Execution/TypeCache.cs
+++ b/src/Adapter/MSTest.CoreAdapter/Execution/TypeCache.cs
@@ -54,7 +54,7 @@ internal class TypeCache : MarshalByRefObject
/// Initializes a new instance of the class.
///
internal TypeCache()
- : this(new ReflectHelper())
+ : this(ReflectHelper.Instance)
{
}
@@ -100,12 +100,12 @@ public TestMethodInfo GetTestMethodInfo(TestMethod testMethod, ITestContext test
{
if (testMethod == null)
{
- throw new ArgumentNullException("testMethod");
+ throw new ArgumentNullException(nameof(testMethod));
}
if (testContext == null)
{
- throw new ArgumentNullException("testContext");
+ throw new ArgumentNullException(nameof(testContext));
}
// Get the classInfo (This may throw as GetType calls assembly.GetType(..,true);)
@@ -682,9 +682,9 @@ private MethodInfo GetMethodInfoUsingRuntimeMethods(TestMethod testMethod, TestC
{
// Only find methods that match the given declaring name.
testMethodInfo =
- methodsInClass.Where(method => method.Name.Equals(testMethod.Name)
+ Array.Find(methodsInClass, method => method.Name.Equals(testMethod.Name)
&& method.DeclaringType.FullName.Equals(testMethod.DeclaringClassFullName)
- && method.HasCorrectTestMethodSignature(true)).FirstOrDefault();
+ && method.HasCorrectTestMethodSignature(true));
}
else
{
diff --git a/src/Adapter/MSTest.CoreAdapter/Execution/UnitTestRunner.cs b/src/Adapter/MSTest.CoreAdapter/Execution/UnitTestRunner.cs
index 679d5a897..ea183f498 100644
--- a/src/Adapter/MSTest.CoreAdapter/Execution/UnitTestRunner.cs
+++ b/src/Adapter/MSTest.CoreAdapter/Execution/UnitTestRunner.cs
@@ -28,7 +28,7 @@ internal class UnitTestRunner : MarshalByRefObject
///
/// Specifies adapter settings that need to be instantiated in the domain running these tests.
public UnitTestRunner(MSTestSettings settings)
- : this(settings, new ReflectHelper())
+ : this(settings, ReflectHelper.Instance)
{
}
@@ -68,7 +68,7 @@ internal UnitTestResult[] RunSingleTest(TestMethod testMethod, IDictionary
/// The to unit test element.
///
@@ -57,13 +69,24 @@ internal static UnitTestElement ToUnitTestElement(this TestCase testCase, string
TestMethod testMethod;
if (testCase.ContainsManagedMethodAndType())
{
- testMethod = new TestMethod(testCase.GetManagedType(), testCase.GetManagedMethod(), name, testClassName, source, isAsync);
+ testMethod = new TestMethod(testCase.GetManagedType(), testCase.GetManagedMethod(), testCase.GetHierarchy(), name, testClassName, source, isAsync);
}
else
{
testMethod = new TestMethod(name, testClassName, source, isAsync);
}
+ var dataType = (DynamicDataType)testCase.GetPropertyValue(Constants.TestDynamicDataTypeProperty, (int)DynamicDataType.None);
+ if (dataType != DynamicDataType.None)
+ {
+ var data = testCase.GetPropertyValue(Constants.TestDynamicDataProperty, null);
+
+ testMethod.DataType = dataType;
+ testMethod.SerializedData = data;
+ }
+
+ testMethod.DisplayName = testCase.DisplayName;
+
if (declaringClassName != null && declaringClassName != testClassName)
{
testMethod.DeclaringClassFullName = declaringClassName;
@@ -77,6 +100,43 @@ internal static UnitTestElement ToUnitTestElement(this TestCase testCase, string
DisplayName = testCase.DisplayName
};
+ if (testCase.Traits.Any())
+ {
+ testElement.Traits = testCase.Traits.ToArray();
+ }
+
+ var cssIteration = testCase.GetPropertyValue(Constants.CssIterationProperty, null);
+ if (!string.IsNullOrWhiteSpace(cssIteration))
+ {
+ testElement.CssIteration = cssIteration;
+ }
+
+ var cssProjectStructure = testCase.GetPropertyValue(Constants.CssProjectStructureProperty, null);
+ if (!string.IsNullOrWhiteSpace(cssIteration))
+ {
+ testElement.CssProjectStructure = cssProjectStructure;
+ }
+
+ var description = testCase.GetPropertyValue(Constants.DescriptionProperty, null);
+ if (!string.IsNullOrWhiteSpace(description))
+ {
+ testElement.Description = description;
+ }
+
+ var workItemIds = testCase.GetPropertyValue(Constants.WorkItemIdsProperty, null);
+ if (workItemIds != null && workItemIds.Length > 0)
+ {
+ testElement.WorkItemIds = workItemIds;
+ }
+
+ var deploymentItems = testCase.GetPropertyValue[]>(Constants.DeploymentItemsProperty, null);
+ if (deploymentItems != null && deploymentItems.Length > 0)
+ {
+ testElement.DeploymentItems = deploymentItems;
+ }
+
+ testElement.DoNotParallelize = testCase.GetPropertyValue(Constants.DoNotParallelizeProperty, false);
+
return testElement;
}
@@ -89,5 +149,9 @@ internal static UnitTestElement ToUnitTestElement(this TestCase testCase, string
internal static void SetManagedMethod(this TestCase testCase, string value) => testCase.SetPropertyValue(ManagedMethodProperty, value);
internal static bool ContainsManagedMethodAndType(this TestCase testCase) => !string.IsNullOrWhiteSpace(testCase.GetManagedMethod()) && !string.IsNullOrWhiteSpace(testCase.GetManagedType());
+
+ internal static string[] GetHierarchy(this TestCase testCase) => testCase.GetPropertyValue(HierarchyProperty, null);
+
+ internal static void SetHierarchy(this TestCase testCase, params string[] value) => testCase.SetPropertyValue(HierarchyProperty, value);
}
}
diff --git a/src/Adapter/MSTest.CoreAdapter/Friends.cs b/src/Adapter/MSTest.CoreAdapter/Friends.cs
index d4224b84e..0b478fdb3 100644
--- a/src/Adapter/MSTest.CoreAdapter/Friends.cs
+++ b/src/Adapter/MSTest.CoreAdapter/Friends.cs
@@ -6,4 +6,5 @@
[assembly: InternalsVisibleTo(assemblyName: "Microsoft.VisualStudio.TestPlatform.MSTestAdapter.UnitTests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
[assembly: InternalsVisibleTo(assemblyName: "DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
-[assembly: InternalsVisibleTo(assemblyName: "MSTestAdapter.Smoke.E2ETests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
\ No newline at end of file
+[assembly: InternalsVisibleTo(assemblyName: "MSTestAdapter.Smoke.E2ETests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
+[assembly: InternalsVisibleTo(assemblyName: "DiscoveryAndExecutionTests, PublicKey=002400000480000094000000060200000024000052534131000400000100010007d1fa57c4aed9f0a32e84aa0faefd0de9e8fd6aec8f87fb03766c834c99921eb23be79ad9d5dcc1dd9ad236132102900b723cf980957fc4e177108fc607774f29e8320e92ea05ece4e821c0a5efe8f1645c4c0c93c1ab99285d622caa652c1dfad63d745d6f2de5f17e5eaf0fc4963d261c8a12436518206dc093344d5ad293")]
diff --git a/src/Adapter/MSTest.CoreAdapter/Helpers/DataSerializationHelper.cs b/src/Adapter/MSTest.CoreAdapter/Helpers/DataSerializationHelper.cs
new file mode 100644
index 000000000..3c99e68b2
--- /dev/null
+++ b/src/Adapter/MSTest.CoreAdapter/Helpers/DataSerializationHelper.cs
@@ -0,0 +1,137 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers
+{
+ using System;
+ using System.Collections.Generic;
+ using System.IO;
+ using System.Linq;
+ using System.Reflection;
+ using System.Runtime.Serialization.Json;
+ using System.Text;
+
+ internal static class DataSerializationHelper
+ {
+ private static readonly Dictionary SerializerCache = new Dictionary();
+ private static readonly DataContractJsonSerializerSettings SerializerSettings = new DataContractJsonSerializerSettings()
+ {
+ UseSimpleDictionaryFormat = true,
+ EmitTypeInformation = System.Runtime.Serialization.EmitTypeInformation.Always,
+ DateTimeFormat = new System.Runtime.Serialization.DateTimeFormat("O", System.Globalization.CultureInfo.InvariantCulture)
+ };
+
+ ///
+ /// Serializes the date in such a way that won't throw exceptions during deserialization in Test Platform.
+ /// The result can be deserialized using method.
+ ///
+ /// Data array to serialize.
+ /// Serialzed array.
+ public static string[] Serialize(object[] data)
+ {
+ if (data == null)
+ {
+ return null;
+ }
+
+ var serializedData = new string[data.Length * 2];
+
+ for (int i = 0; i < data.Length; i++)
+ {
+ var typeIndex = i * 2;
+ var dataIndex = typeIndex + 1;
+
+ if (data[i] == null)
+ {
+ serializedData[typeIndex] = null;
+ serializedData[dataIndex] = null;
+
+ continue;
+ }
+
+ var type = data[i].GetType();
+ var typeName = type.AssemblyQualifiedName;
+
+ serializedData[typeIndex] = typeName;
+
+ var serializer = GetSerializer(type);
+
+ using (var memoryStream = new MemoryStream())
+ {
+ serializer.WriteObject(memoryStream, data[i]);
+ var serializerData = memoryStream.ToArray();
+
+ serializedData[dataIndex] = Encoding.UTF8.GetString(serializerData, 0, serializerData.Length);
+ }
+ }
+
+ return serializedData;
+ }
+
+ ///
+ /// Deserialzes the data serialzed by method.
+ ///
+ /// Serialized data array to deserialize.
+ /// Deserialized array.
+ public static object[] Deserialize(string[] serializedData)
+ {
+ if (serializedData == null || serializedData.Length % 2 != 0)
+ {
+ return null;
+ }
+
+ var length = serializedData.Length / 2;
+ var data = new object[length];
+
+ for (int i = 0; i < length; i++)
+ {
+ var typeIndex = i * 2;
+ var typeName = serializedData[typeIndex];
+ var serializedValue = serializedData[typeIndex + 1];
+
+ if (serializedValue == null || typeName == null)
+ {
+ data[i] = null;
+ continue;
+ }
+
+ var serializer = GetSerializer(typeName);
+
+ var serialzedDataBytes = Encoding.UTF8.GetBytes(serializedValue);
+ using (var memoryStream = new MemoryStream(serialzedDataBytes))
+ {
+ data[i] = serializer.ReadObject(memoryStream);
+ }
+ }
+
+ return data;
+ }
+
+ private static DataContractJsonSerializer GetSerializer(string typeName)
+ {
+ var serializer = SerializerCache.SingleOrDefault(i => i.Key.FullName == typeName);
+ if (serializer.Value != null)
+ {
+ return serializer.Value;
+ }
+
+ var type = Type.GetType(typeName);
+ if (type != null)
+ {
+ return GetSerializer(type);
+ }
+
+ return GetSerializer(typeof(object));
+ }
+
+ private static DataContractJsonSerializer GetSerializer(Type type)
+ {
+ if (SerializerCache.ContainsKey(type))
+ {
+ return SerializerCache[type];
+ }
+
+ return SerializerCache[type] = new DataContractJsonSerializer(type, SerializerSettings);
+ }
+ }
+}
diff --git a/src/Adapter/MSTest.CoreAdapter/Helpers/ReflectHelper.cs b/src/Adapter/MSTest.CoreAdapter/Helpers/ReflectHelper.cs
index 22224a405..7c7a681ca 100644
--- a/src/Adapter/MSTest.CoreAdapter/Helpers/ReflectHelper.cs
+++ b/src/Adapter/MSTest.CoreAdapter/Helpers/ReflectHelper.cs
@@ -18,10 +18,18 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Helpers
internal class ReflectHelper : MarshalByRefObject
{
+ private static readonly Lazy InstanceValue = new Lazy(() => new ReflectHelper());
+
///
/// Contains the memberInfo Vs the name/type of the attributes defined on that member. (FYI: - MemberInfo denotes properties, fields, methods, events)
///
- private Dictionary> attributeCache = new Dictionary>();
+ private readonly Dictionary> attributeCache = new Dictionary>();
+
+ internal ReflectHelper()
+ {
+ }
+
+ public static ReflectHelper Instance => InstanceValue.Value;
///
/// Checks to see if the parameter memberInfo contains the parameter attribute or not.
@@ -113,7 +121,7 @@ public bool HasAttributeDerivedFrom(MemberInfo memberInfo, Type baseAttributeTyp
Dictionary attributes = this.GetAttributes(memberInfo, inherit);
if (attributes == null)
{
- PlatformServiceProvider.Instance.AdapterTraceLogger.LogWarning("ReflectHelper.HasAttributeDerivedFrom: Failed to get attribute cache. Ignoring attribute inheritance and falling into 'type defines Attribute model', so that we have some data.");
+ PlatformServiceProvider.Instance.AdapterTraceLogger.LogWarning($"{nameof(ReflectHelper)}.{nameof(GetAttributes)}: {Resource.FailedFetchAttributeCache}");
return this.IsAttributeDefined(memberInfo, baseAttributeType, inherit);
}
@@ -121,7 +129,7 @@ public bool HasAttributeDerivedFrom(MemberInfo memberInfo, Type baseAttributeTyp
// Try to find the attribute that is derived from baseAttrType.
foreach (object attribute in attributes.Values)
{
- Debug.Assert(attribute != null, "ReflectHeler.DefinesAttributeDerivedFrom: internal error: wrong value in the attrs dictionary.");
+ Debug.Assert(attribute != null, $"{nameof(ReflectHelper)}.{nameof(GetAttributes)}: internal error: wrong value in the attrs dictionary.");
Type attributeType = attribute.GetType();
if (attributeType.GetTypeInfo().IsSubclassOf(baseAttributeType))
@@ -200,6 +208,23 @@ public override object InitializeLifetimeService()
return null;
}
+ internal static T[] GetAttributes(MethodBase methodBase, bool inherit)
+ where T : Attribute
+ {
+ Attribute[] attributeArray = GetCustomAttributes(methodBase, typeof(T), inherit);
+ if (attributeArray == null || attributeArray.Length == 0)
+ {
+ return null;
+ }
+
+ if (attributeArray is T[] attributes)
+ {
+ return attributes;
+ }
+
+ return attributeArray.Where(a => a is T).Cast().ToArray();
+ }
+
///
/// Match return type of method.
///
@@ -629,7 +654,6 @@ private IEnumerable GetTestPropertyAttributes(MemberInfo propertyAttr
/// The member to inspect.
/// Look at inheritance chain.
/// attributes defined.
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Requirement is to handle all kinds of user exceptions and message appropriately.")]
private Dictionary GetAttributes(MemberInfo memberInfo, bool inherit)
{
// If the information is cached, then use it otherwise populate the cache using
@@ -658,16 +682,10 @@ private IEnumerable GetTestPropertyAttributes(MemberInfo propertyAttr
}
catch (Exception ex2)
{
- description =
- ex.GetType().FullName +
- ": (Failed to get exception description due to an exception of type " +
- ex2.GetType().FullName + ')';
+ description = string.Format(CultureInfo.CurrentCulture, Resource.ExceptionOccuredWhileGettingTheExceptionDescription, ex.GetType().FullName, ex2.GetType().FullName); // ex.GetType().FullName +
}
- PlatformServiceProvider.Instance.AdapterTraceLogger.LogWarning(
- "Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1}",
- memberInfo.GetType().FullName,
- description);
+ PlatformServiceProvider.Instance.AdapterTraceLogger.LogWarning(Resource.FailedToGetCustomAttribute, memberInfo.GetType().FullName, description);
// Since we cannot check by attribute names, do it in reflection way.
// Note 1: this will not work for different version of assembly but it is better than nothing.
diff --git a/src/Adapter/MSTest.CoreAdapter/MSTest.CoreAdapter.csproj b/src/Adapter/MSTest.CoreAdapter/MSTest.CoreAdapter.csproj
index f02086162..23dcee5f1 100644
--- a/src/Adapter/MSTest.CoreAdapter/MSTest.CoreAdapter.csproj
+++ b/src/Adapter/MSTest.CoreAdapter/MSTest.CoreAdapter.csproj
@@ -1,9 +1,7 @@
-
- ..\..\..\
-
-
+
+
{98BA6D2C-1F3D-4636-8E1D-D4932B7A253D}
Library
@@ -29,6 +27,46 @@
prompt
4
+
+
+
+ C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETPortable\v4.5\System.Collections.Concurrent.dll
+
+
+
+ {bbc99a6b-4490-49dd-9c12-af2c1e95576e}
+ PlatformServices.Interface
+ False
+
+
+ {58bdd63d-5e58-4d23-bdf5-592e5e03d29d}
+ PlatformServices.Portable
+ False
+
+
+ {7252d9e3-267d-442c-96bc-c73aef3241d6}
+ MSTest.Core
+ False
+
+
+ {6c9fe494-8315-4667-b3f6-75dc62a62319}
+ Extension.Core
+ False
+
+
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
@@ -38,6 +76,7 @@
+
@@ -54,6 +93,7 @@
+
@@ -88,37 +128,9 @@
Resource.resx
-
-
-
- {6c9fe494-8315-4667-b3f6-75dc62a62319}
- Extension.Core
- False
-
-
- {7252d9e3-267d-442c-96bc-c73aef3241d6}
- MSTest.Core
- False
-
-
- {bbc99a6b-4490-49dd-9c12-af2c1e95576e}
- PlatformServices.Interface
- False
-
-
- {58bdd63d-5e58-4d23-bdf5-592e5e03d29d}
- PlatformServices.Portable
- False
-
-
-
+
-
-
- C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETPortable\v4.5\System.Collections.Concurrent.dll
-
-
ResXFileCodeGenerator
@@ -126,21 +138,22 @@
Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter
-
-
-
-
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
-
- $(ProjectDir)..\Build
-
- xcopy /Y /I /S /E "$(SourcePath)" "$(OutDir)..\Build"
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Adapter/MSTest.CoreAdapter/MSTestDiscoverer.cs b/src/Adapter/MSTest.CoreAdapter/MSTestDiscoverer.cs
index 8179dd273..5ccfab718 100644
--- a/src/Adapter/MSTest.CoreAdapter/MSTestDiscoverer.cs
+++ b/src/Adapter/MSTest.CoreAdapter/MSTestDiscoverer.cs
@@ -80,7 +80,7 @@ internal bool AreValidSources(IEnumerable sources)
source =>
PlatformServiceProvider.Instance.TestSource.ValidSourceExtensions.Any(
extension =>
- string.Compare(Path.GetExtension(source), extension, StringComparison.OrdinalIgnoreCase) == 0));
+ string.Equals(Path.GetExtension(source), extension, StringComparison.OrdinalIgnoreCase)));
}
}
}
diff --git a/src/Adapter/MSTest.CoreAdapter/MSTestSettings.cs b/src/Adapter/MSTest.CoreAdapter/MSTestSettings.cs
index a6fd56243..351491782 100644
--- a/src/Adapter/MSTest.CoreAdapter/MSTestSettings.cs
+++ b/src/Adapter/MSTest.CoreAdapter/MSTestSettings.cs
@@ -245,7 +245,7 @@ public static bool IsLegacyScenario(IMessageLogger logger)
///
/// Gets the adapter specific settings from the xml.
///
- /// The xml with the settings passed from the test platform.
+ /// The xml with the settings passed from the test platform.
/// The name of the adapter settings to fetch - Its either MSTest or MSTestV2
/// The settings if found. Null otherwise.
internal static MSTestSettings GetSettings(string runSettingsXml, string settingName)
diff --git a/src/Adapter/MSTest.CoreAdapter/ObjectModel/DynamicDataType.cs b/src/Adapter/MSTest.CoreAdapter/ObjectModel/DynamicDataType.cs
new file mode 100644
index 000000000..b1b82712c
--- /dev/null
+++ b/src/Adapter/MSTest.CoreAdapter/ObjectModel/DynamicDataType.cs
@@ -0,0 +1,12 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel
+{
+ internal enum DynamicDataType : int
+ {
+ None = 0,
+ DataSourceAttribute = 1,
+ ITestDataSource = 2
+ }
+}
diff --git a/src/Adapter/MSTest.CoreAdapter/ObjectModel/TestMethod.cs b/src/Adapter/MSTest.CoreAdapter/ObjectModel/TestMethod.cs
index 1d0a4f80f..210fd9d55 100644
--- a/src/Adapter/MSTest.CoreAdapter/ObjectModel/TestMethod.cs
+++ b/src/Adapter/MSTest.CoreAdapter/ObjectModel/TestMethod.cs
@@ -4,9 +4,12 @@
namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel
{
using System;
+ using System.Collections.Generic;
+ using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Reflection;
+ using Microsoft.TestPlatform.AdapterUtilities;
using Microsoft.TestPlatform.AdapterUtilities.ManagedNameUtilities;
using MSTestAdapter.PlatformServices.Interface.ObjectModel;
@@ -17,18 +20,15 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel
[Serializable]
public sealed class TestMethod : ITestMethod
{
- #region Fields
-
///
- /// Member field for the property 'DeclaringClassFullName'
+ /// Number of elements in .
///
- private string declaringClassFullName = null;
+ public const int TotalHierarchyLevels = HierarchyConstants.Levels.TotalLevelCount;
- ///
- /// Member field for the property 'DeclaringAssemblyName'
- ///
+ #region Fields
+ private IReadOnlyCollection hierarchy;
+ private string declaringClassFullName = null;
private string declaringAssemblyName = null;
-
#endregion
public TestMethod(string name, string fullClassName, string assemblyName, bool isAsync)
@@ -45,6 +45,12 @@ public TestMethod(string name, string fullClassName, string assemblyName, bool i
this.FullClassName = fullClassName;
this.AssemblyName = assemblyName;
this.IsAsync = isAsync;
+
+ var hierarchy = new string[HierarchyConstants.Levels.TotalLevelCount];
+ hierarchy[HierarchyConstants.Levels.NamespaceIndex] = fullClassName;
+ hierarchy[HierarchyConstants.Levels.ClassIndex] = name;
+
+ this.hierarchy = new ReadOnlyCollection(hierarchy);
}
internal TestMethod(MethodBase method, string name, string fullClassName, string assemblyName, bool isAsync)
@@ -55,33 +61,25 @@ internal TestMethod(MethodBase method, string name, string fullClassName, string
throw new ArgumentNullException(nameof(method));
}
- ManagedNameHelper.GetManagedName(method, out var managedType, out var managedMethod);
-
- // ManagedNameHelpers currently does not support spaces in method names.
- // If there are spaces in the method name, we'll use the legacy way to find the method.
- if (!managedMethod.Contains(" "))
- {
- this.ManagedTypeName = managedType;
- this.ManagedMethodName = managedMethod;
- }
+ ManagedNameHelper.GetManagedName(method, out var managedType, out var managedMethod, out var hierarchyValues);
+ this.ManagedTypeName = managedType;
+ this.ManagedMethodName = managedMethod;
+ this.hierarchy = new ReadOnlyCollection(hierarchyValues);
}
- internal TestMethod(string managedTypeName, string managedMethodName, string name, string fullClassName, string assemblyName, bool isAsync)
+ internal TestMethod(string managedTypeName, string managedMethodName, string[] hierarchyValues, string name, string fullClassName, string assemblyName, bool isAsync)
: this(name, fullClassName, assemblyName, isAsync)
{
this.ManagedTypeName = managedTypeName;
this.ManagedMethodName = managedMethodName;
+ this.hierarchy = new ReadOnlyCollection(hierarchyValues);
}
- ///
- /// Gets the name of the test method
- ///
- public string Name { get; private set; }
+ ///
+ public string Name { get; }
- ///
- /// Gets the full classname of the test method
- ///
- public string FullClassName { get; private set; }
+ ///
+ public string FullClassName { get; }
///
/// Gets or sets the declaring assembly full name. This will be used while getting navigation data.
@@ -136,5 +134,30 @@ public string DeclaringClassFullName
///
public bool HasManagedMethodAndTypeProperties => !string.IsNullOrWhiteSpace(this.ManagedTypeName) && !string.IsNullOrWhiteSpace(this.ManagedMethodName);
+
+ ///
+ public IReadOnlyCollection Hierarchy => this.hierarchy;
+
+ ///
+ /// Gets or sets type of dynamic data if any
+ ///
+ internal DynamicDataType DataType { get; set; }
+
+ ///
+ /// Gets or sets the serialized data
+ ///
+ internal string[] SerializedData { get; set; }
+
+ ///
+ /// Gets or sets the test group set during discovery
+ ///
+ internal string TestGroup { get; set; }
+
+ ///
+ /// Gets or sets the display name set during discovery
+ ///
+ internal string DisplayName { get; set; }
+
+ internal TestMethod Clone() => this.MemberwiseClone() as TestMethod;
}
}
diff --git a/src/Adapter/MSTest.CoreAdapter/ObjectModel/UnitTestElement.cs b/src/Adapter/MSTest.CoreAdapter/ObjectModel/UnitTestElement.cs
index b9b8d13bc..c1b38dacd 100644
--- a/src/Adapter/MSTest.CoreAdapter/ObjectModel/UnitTestElement.cs
+++ b/src/Adapter/MSTest.CoreAdapter/ObjectModel/UnitTestElement.cs
@@ -7,7 +7,10 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
+ using System.IO;
+ using System.Linq;
+ using Microsoft.TestPlatform.AdapterUtilities;
using Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.Extensions;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
@@ -15,6 +18,7 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter.ObjectModel
/// The unit test element.
///
[Serializable]
+ [DebuggerDisplay("{GetDisplayName()} ({TestMethod.ManagedTypeName})")]
internal class UnitTestElement
{
///
@@ -103,6 +107,17 @@ public UnitTestElement(TestMethod testMethod)
///
internal string[] WorkItemIds { get; set; }
+ internal UnitTestElement Clone()
+ {
+ var clone = this.MemberwiseClone() as UnitTestElement;
+ if (this.TestMethod != null)
+ {
+ clone.TestMethod = this.TestMethod.Clone();
+ }
+
+ return clone;
+ }
+
///
/// Convert the UnitTestElement instance to an Object Model testCase instance.
///
@@ -129,6 +144,12 @@ internal TestCase ToTestCase()
testCase.SetPropertyValue(TestAdapter.Constants.TestClassNameProperty, this.TestMethod.FullClassName);
}
+ var hierarchy = this.TestMethod.Hierarchy;
+ if (hierarchy != null && hierarchy.Count > 0)
+ {
+ testCase.SetHierarchy(hierarchy.ToArray());
+ }
+
// Set declaring type if present so the correct method info can be retrieved
if (this.TestMethod.DeclaringClassFullName != null)
{
@@ -190,6 +211,44 @@ internal TestCase ToTestCase()
testCase.SetPropertyValue(TestAdapter.Constants.DoNotParallelizeProperty, this.DoNotParallelize);
}
+ // Store resolved data if any
+ if (this.TestMethod.DataType != DynamicDataType.None)
+ {
+ var data = this.TestMethod.SerializedData;
+
+ testCase.SetPropertyValue(TestAdapter.Constants.TestDynamicDataTypeProperty, (int)this.TestMethod.DataType);
+ testCase.SetPropertyValue(TestAdapter.Constants.TestDynamicDataProperty, data);
+ }
+
+ string fileName = testCase.Source;
+ try
+ {
+ fileName = Path.GetFileName(fileName);
+ }
+ catch
+ {
+ }
+
+ var idProvider = new TestIdProvider();
+ idProvider.AppendString(testCase.ExecutorUri?.ToString());
+ idProvider.AppendString(fileName);
+ if (this.TestMethod.HasManagedMethodAndTypeProperties)
+ {
+ idProvider.AppendString(this.TestMethod.ManagedTypeName);
+ idProvider.AppendString(this.TestMethod.ManagedMethodName);
+ }
+ else
+ {
+ idProvider.AppendString(testCase.FullyQualifiedName);
+ }
+
+ if (this.TestMethod.DataType != DynamicDataType.None)
+ {
+ idProvider.AppendString(testCase.DisplayName);
+ }
+
+ testCase.Id = idProvider.GetId();
+
return testCase;
}
diff --git a/src/Adapter/MSTest.CoreAdapter/Resources/Resource.Designer.cs b/src/Adapter/MSTest.CoreAdapter/Resources/Resource.Designer.cs
index 4724a2c69..6d880c368 100644
--- a/src/Adapter/MSTest.CoreAdapter/Resources/Resource.Designer.cs
+++ b/src/Adapter/MSTest.CoreAdapter/Resources/Resource.Designer.cs
@@ -20,7 +20,7 @@ namespace Microsoft.VisualStudio.TestPlatform.MSTest.TestAdapter {
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
- [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resource {
@@ -70,6 +70,33 @@ internal class Resource {
}
}
+ ///
+ /// Looks up a localized string similar to Exception occurred while enumarating DataSourceAttribute on "{0}.{1}": {2}.
+ ///
+ internal static string CannotEnumerateDataSourceAttribute {
+ get {
+ return ResourceManager.GetString("CannotEnumerateDataSourceAttribute", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to A test method can only contain one DataSourceAttribute, but found {2} on "{0}.{1}"..
+ ///
+ internal static string CannotEnumerateDataSourceAttribute_MoreThenOneDefined {
+ get {
+ return ResourceManager.GetString("CannotEnumerateDataSourceAttribute_MoreThenOneDefined", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Exception occurred while enumarating IDataSource attribute on "{0}.{1}": {2}.
+ ///
+ internal static string CannotEnumerateIDataSourceAttribute {
+ get {
+ return ResourceManager.GetString("CannotEnumerateIDataSourceAttribute", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to The parameter should not be null or empty..
///
@@ -142,6 +169,24 @@ internal class Resource {
}
}
+ ///
+ /// Looks up a localized string similar to "{0}": (Failed to get exception description due to an exception of type "{1}"..
+ ///
+ internal static string ExceptionOccuredWhileGettingTheExceptionDescription {
+ get {
+ return ResourceManager.GetString("ExceptionOccuredWhileGettingTheExceptionDescription", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Exceptions thrown:.
+ ///
+ internal static string ExceptionsThrown {
+ get {
+ return ResourceManager.GetString("ExceptionsThrown", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Test '{0}' execution has been aborted..
///
@@ -160,6 +205,24 @@ internal class Resource {
}
}
+ ///
+ /// Looks up a localized string similar to Failed to get attribute cache. Ignoring attribute inheritance and falling into 'type defines Attribute model', so that we have some data..
+ ///
+ internal static string FailedFetchAttributeCache {
+ get {
+ return ResourceManager.GetString("FailedFetchAttributeCache", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1}.
+ ///
+ internal static string FailedToGetCustomAttribute {
+ get {
+ return ResourceManager.GetString("FailedToGetCustomAttribute", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Invalid value '{0}' specified for 'Scope'. Supported scopes are {1}..
///
@@ -205,6 +268,15 @@ internal class Resource {
}
}
+ ///
+ /// Looks up a localized string similar to An older version of MSTestV2 package is loaded in assembly, test discovery might fail to discover all data tests if they depend on `.runsettings` file..
+ ///
+ internal static string OlderTFMVersionFound {
+ get {
+ return ResourceManager.GetString("OlderTFMVersionFound", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Running tests in any of the provided sources is not supported for the selected platform.
///
@@ -495,7 +567,7 @@ internal class Resource {
}
///
- /// Looks up a localized string similar to Exception thrown while executing test. If using extension of TestMethodAttribute then please contact vendor. Error message: {0}.
+ /// Looks up a localized string similar to Exception thrown while executing test. If using extension of TestMethodAttribute then please contact vendor. Error message: {0}, Stack trace: {1}.
///
internal static string UTA_ExecuteThrewException {
get {
@@ -640,6 +712,15 @@ internal class Resource {
}
}
+ ///
+ /// Looks up a localized string similar to The called code threw an exception that was caught, but the exception value was null.
+ ///
+ internal static string UTA_UserCodeThrewNullValueException {
+ get {
+ return ResourceManager.GetString("UTA_UserCodeThrewNullValueException", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to {0} For UWP projects, if you are using UI objects in test consider using [UITestMethod] attribute instead of [TestMethod] to execute test in UI thread..
///
diff --git a/src/Adapter/MSTest.CoreAdapter/Resources/Resource.resx b/src/Adapter/MSTest.CoreAdapter/Resources/Resource.resx
index 474f4ed5d..872c6ab19 100644
--- a/src/Adapter/MSTest.CoreAdapter/Resources/Resource.resx
+++ b/src/Adapter/MSTest.CoreAdapter/Resources/Resource.resx
@@ -209,7 +209,7 @@ Error: {1}
Class Initialization method {0}.{1} threw exception. {2}: {3}.
- Exception thrown while executing test. If using extension of TestMethodAttribute then please contact vendor. Error message: {0}
+ Exception thrown while executing test. If using extension of TestMethodAttribute then please contact vendor. Error message: {0}, Stack trace: {1}
Error in executing test. No result returned by extension. If using extension of TestMethodAttribute then please contact vendor.
@@ -320,4 +320,45 @@ Error: {1}
Test '{0}' execution has been aborted.
+
+ Exception occurred while enumarating DataSourceAttribute on "{0}.{1}": {2}
+ {0}: TypeName with namespace,
+{1}: Method name,
+{2}: Exception details
+
+
+ A test method can only contain one DataSourceAttribute, but found {2} on "{0}.{1}".
+ {0}: TypeName with namespace,
+{1}: Method name,
+{2}: Number of attributed defined.
+
+
+ Exception occurred while enumarating IDataSource attribute on "{0}.{1}": {2}
+ {0}: TypeName with namespace,
+{1}: Method name,
+{2}: Exception details
+
+
+ "{0}": (Failed to get exception description due to an exception of type "{1}".
+ {0}: Type of the original exception that we're trying to get the desciption of.
+{1}: Thrown exception
+
+
+ Exceptions thrown:
+ This is usually preceeds by TestAssembly_AssemblyDiscoveryFailure message, and precceded by list of exceptions thrown in a test discovery session.
+
+
+ Failed to get attribute cache. Ignoring attribute inheritance and falling into 'type defines Attribute model', so that we have some data.
+
+
+ Getting custom attributes for type {0} threw exception (will ignore and use the reflection way): {1}
+ {0}: Attribute full type name.
+{1}: Exception description
+
+
+ An older version of MSTestV2 package is loaded in assembly, test discovery might fail to discover all data tests if they depend on `.runsettings` file.
+
+
+ The called code threw an exception that was caught, but the exception value was null
+
\ No newline at end of file
diff --git a/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.cs.xlf b/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.cs.xlf
index 6f77f6ae5..aa8544f0d 100644
--- a/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.cs.xlf
+++ b/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.cs.xlf
@@ -1,407 +1,343 @@
-
-
-
-
-
-
- Test {0} překročil časový limit spuštění.
-
-
-
-
-
- Spouštění testů v některém z uvedených zdrojů se pro vybranou platformu nepodporuje.
-
-
-
-
-
- Metoda TestCleanup {0}.{1} způsobila výjimku. {2}: {3}.
-
-
-
-
-
- --- Konec trasování zásobníku pro vnitřní výjimku ---
-
-
-
-
-
- UTA014: {0}: V jednom sestavení nejde definovat více jak jednu metodu s atributem AssemblyCleanup.
-
-
-
-
-
- UTA013: {0}: V jednom sestavení nejde definovat více jak jednu metodu s atributem AssemblyInitialize.
-
-
-
-
-
- UTA026: {0}: Uvnitř třídy nejde definovat více jak jednu metodu s atributem ClassCleanup.
-
-
-
-
-
- UTA025: {0}: Uvnitř třídy nejde definovat více jak jednu metodu s atributem ClassInitialize.
-
-
-
-
-
- UTA024: {0}: Nejde definovat více jak jednu metodu s atributem TestCleanup.
-
-
-
-
-
- UTA018: {0}: Nejde definovat více jak jednu metodu s atributem TestInitialize.
-
-
-
-
-
- Inicializační metoda {0}.{1} způsobila výjimku. {2}.
-
-
-
-
-
- Nepodařilo se vytvořit instanci třídy {0}. Chyba: {1}.
-
-
-
-
-
- Pro třídu {0} se nepodařilo nastavit vlastnost TestContext. Chyba: {1}.
-
-
-
-
-
- (Z důvodu výjimky se nepodařilo získat zprávu o výjimce typu {0}.)
-
-
-
-
-
- UTA031: Třída {0} neobsahuje platnou vlastnost TestContext. Vlastnost TestContext musí být typu TestContext, musí být nestatická, veřejná a nemůže být určena jenom pro čtení. Například: public TestContext TestContext.
-
-
-
-
-
- UTA001: Atribut TestClass se definoval v neveřejné třídě {0}.
-
-
-
-
-
- MSTestAdapter nezjistil v třídě {0} sestavení {1} žádný test, protože: {2}.
-
-
-
-
-
- {0}: {1}
-
-
-
-
-
- Nepovedlo se načíst typy ze zdroje testu {0}. Je možné, že se některé nebo všechny testy v tomto zdroji nezjistily.
-Chyba: {1}
-
-
-
-
-
- UTA015: Obecná metoda nemůže být testovací metodou. {0}.{1} má neplatný podpis.
-
-
-
-
-
- Parametr nemůže být null nebo prázdný.
-
-
-
-
-
- Parametr musí být vetší než nula.
-
-
-
-
-
- MSTestAdapter nezjistil v třídě {0} sestavení {1} žádný test. Důvod {2}.
-
-
-
-
-
- Neexistující soubor: {0}
-
-
-
-
-
- UTA007: Metoda {1} definovaná ve třídě {0} nemá správný podpis. Testovací metoda označená pomocí atributu [TestMethod] musí být nestatická, veřejná, nesmí vracet žádnou hodnotu a neměla by mít žádné parametry. Například: public void Test.Class1.Test(). Navíc pokud v testovací metodě používáte asynchronní čekání, musí návratový typ být Task. Například: public Task Test.Class1.Test2()
-
-
-
-
-
- TestContext nemůže být Null.
-
-
-
-
-
- Čisticí metoda sestavení {0}.{1} selhala. Chybová zpráva: {2}. Trasování zásobníku: {3}
-
-
-
-
-
- Inicializační metoda sestavení {0}.{1} vyvolala výjimku. {2}: {3}. Přerušuje se provádění testu.
-
-
-
-
-
- Čisticí metoda třídy {0}.{1} selhala. Chybová zpráva: {2}. Trasování zásobníku: {3}
-
-
-
-
-
- Inicializační metoda třídy {0}.{1} vyvolala výjimku. {2}: {3}.
-
-
-
-
-
- Při provádění testu došlo k výjimce. Pokud používáte rozšíření třídy TestMethodAttribute, obraťte se na dodavatele. Chybová zpráva: {0}
-
-
-
-
-
- Při provádění testu došlo k chybě. Rozšíření nevrátilo žádný výsledek. Pokud používáte rozšíření třídy TestMethodAttribute, obraťte se na dodavatele.
-
-
-
-
-
- Metoda {0}.{1} má špatný podpis. Metoda musí být statická, veřejná, nevracet hodnotu a nepřijímat žádné parametry. Pokud navíc v metodě používáte operátor async-await, musí být návratový typ Task.
-
-
-
-
-
- Metoda {0}.{1} má špatný podpis. Metoda musí být statická, veřejná, nevracet hodnotu a přijímat jeden parametr typu TestContext. Pokud navíc v metodě používáte operátor async-await, musí být návratový typ Task.
-
-
-
-
-
- UTA054: {0}.{1} má neplatný atribut Timeout. Timeout musí být platné celé číslo a nesmí být menší než 0.
-
-
-
-
-
- UTA023: {0}: V metodě {1} nejde definovat předdefinovanou vlastnost {2}.
-
-
-
-
-
- UTA022: {0}.{1}: Vlastní vlastnost {2} je už definovaná. Použije se hodnota {3}.
-
-
-
-
-
- UTA021: {0}: V metodě {1} je definovaná vlastní vlastnost, která je null nebo je prázdná. Vlastní vlastnost musí mít platný název.
-
-
-
-
-
- Metoda {0}.{1} neexistuje.
-
-
-
-
-
- Pro třídu {0} se nepodařilo najít výchozí konstruktor.
-
-
-
-
-
- Nepodařilo se najít vlastnost {0}.TestContext. Chyba:{1}.
-
-
-
-
-
- {0}.TestContext má nesprávný typ.
-
-
-
-
-
- Metoda {0}.{1} má chybný podpis. Metoda musí být nestatická, veřejná, nevracet hodnotu a nepřijímat žádný parametr. Pokud navíc v metodě používáte operátor async-await, musí být návratový typ Task.
-
-
-
-
-
- Nepodařilo se získat typ {0}. Chyba: {1}.
-
-
-
-
-
- Testovací metoda {0} se nenašla.
-
-
-
-
-
- Trasování ladění:
-
-
-
-
-
- Nepovedlo se získat výjimku vyvolanou testovací metodou {0}.{1}.
-
-
-
-
-
- V testovací metodě {0}.{1} došlo k výjimce:
-{2}
-
-
-
-
-
- {0}. Pokud v testu používáte objekty uživatelského rozhraní, zvažte u projektů pro platformu UPW použití atributu [UITestMethod] místo atributu [TestMethod], aby se test provedl ve vlákně uživatelského rozhraní.
-
-
-
-
-
- MSTestAdapterV2
-
-
-
-
-
- Neplatné nastavení {0}. Neočekávaný XmlAttribute: {1}.
-
-
-
-
-
- Neplatné nastavení {0}. Neočekávaný XmlElement: {1}.
-
-
-
-
-
- {0} (datový řádek {1})
-
-
-
-
-
- Atribut ExpectedException definovaný u testovací metody {0}.{1} vyvolal během vytváření výjimku.
-{2}
-
-
-
-
-
- Testovací metoda {0}.{1} má definovaných více atributů odvozených od atributu ExpectedExceptionBaseAttribute. Povolený je jenom jeden takový atribut.
-
-
-
-
-
- Upozornění: Adaptér MSTest V2 nepodporuje soubor testsettings ani vsmdi.
-
-
-
-
-
- Zprávy pro TestContext:
-
-
-
-
-
- Při volání čisticí metody testu pro třídu {0} došlo k chybě: {1}
-
-
-
-
-
- Trasování zásobníku čištění testu
-
-
-
-
-
- [MSTest][Discovery][{0}] {1}
-
-
-
-
-
- Prováděcí modul MSTest: Je povolená paralelizace testu pro {0} (pracovní procesy: {1}, obor: {2}).
-
-
-
-
-
- Pro Obor je zadaná neplatná hodnota {0}. Podporované obory jsou {1}.
- 'Scope' is a setting name that shouldn't be localized.
-
-
-
- Pro Pracovní procesy je zadaná neplatná hodnota {0}. Hodnota by měla být nezáporné celé číslo.
- `Workers` is a setting name that shouldn't be localized.
-
-
-
- Nepovedlo se zjistit testy ze sestavení {0}. Důvod:{1}
-
-
-
-
-
- Parametry můžou mít pouze testovací metody řízené daty. Nechtěli jste použít atribut [DataRow] nebo [DynamicData]?
-
-
-
-
-
- Spouštění testu {0} se přerušilo.
-
-
-
-
-
+
+
+
+
+
+
+ Test {0} překročil časový limit spuštění.
+
+
+
+
+ Spouštění testů v některém z uvedených zdrojů se pro vybranou platformu nepodporuje.
+
+
+
+
+ Metoda TestCleanup {0}.{1} způsobila výjimku. {2}: {3}.
+
+
+
+
+ --- Konec trasování zásobníku pro vnitřní výjimku ---
+
+
+
+
+ UTA014: {0}: V jednom sestavení nejde definovat více jak jednu metodu s atributem AssemblyCleanup.
+
+
+
+
+ UTA013: {0}: V jednom sestavení nejde definovat více jak jednu metodu s atributem AssemblyInitialize.
+
+
+
+
+ UTA026: {0}: Uvnitř třídy nejde definovat více jak jednu metodu s atributem ClassCleanup.
+
+
+
+
+ UTA025: {0}: Uvnitř třídy nejde definovat více jak jednu metodu s atributem ClassInitialize.
+
+
+
+
+ UTA024: {0}: Nejde definovat více jak jednu metodu s atributem TestCleanup.
+
+
+
+
+ UTA018: {0}: Nejde definovat více jak jednu metodu s atributem TestInitialize.
+
+
+
+
+ Inicializační metoda {0}.{1} způsobila výjimku. {2}.
+
+
+
+
+ Nepodařilo se vytvořit instanci třídy {0}. Chyba: {1}.
+
+
+
+
+ Pro třídu {0} se nepodařilo nastavit vlastnost TestContext. Chyba: {1}.
+
+
+
+
+ (Z důvodu výjimky se nepodařilo získat zprávu o výjimce typu {0}.)
+
+
+
+
+ UTA031: Třída {0} neobsahuje platnou vlastnost TestContext. Vlastnost TestContext musí být typu TestContext, musí být nestatická, veřejná a nemůže být určena jenom pro čtení. Například: public TestContext TestContext.
+
+
+
+
+ UTA001: Atribut TestClass se definoval v neveřejné třídě {0}.
+
+
+
+
+ MSTestAdapter nezjistil v třídě {0} sestavení {1} žádný test, protože: {2}.
+
+
+
+
+ {0}: {1}
+
+
+
+
+ Nepovedlo se načíst typy ze zdroje testu {0}. Je možné, že se některé nebo všechny testy v tomto zdroji nezjistily.
+Chyba: {1}
+
+
+
+
+ UTA015: Obecná metoda nemůže být testovací metodou. {0}.{1} má neplatný podpis.
+
+
+
+
+ Parametr nemůže být null nebo prázdný.
+
+
+
+
+ Parametr musí být vetší než nula.
+
+
+
+
+ MSTestAdapter nezjistil v třídě {0} sestavení {1} žádný test. Důvod {2}.
+
+
+
+
+ Neexistující soubor: {0}
+
+
+
+
+ UTA007: Metoda {1} definovaná ve třídě {0} nemá správný podpis. Testovací metoda označená pomocí atributu [TestMethod] musí být nestatická, veřejná, nesmí vracet žádnou hodnotu a neměla by mít žádné parametry. Například: public void Test.Class1.Test(). Navíc pokud v testovací metodě používáte asynchronní čekání, musí návratový typ být Task. Například: public Task Test.Class1.Test2()
+
+
+
+
+ TestContext nemůže být Null.
+
+
+
+
+ Čisticí metoda sestavení {0}.{1} selhala. Chybová zpráva: {2}. Trasování zásobníku: {3}
+
+
+
+
+ Inicializační metoda sestavení {0}.{1} vyvolala výjimku. {2}: {3}. Přerušuje se provádění testu.
+
+
+
+
+ Čisticí metoda třídy {0}.{1} selhala. Chybová zpráva: {2}. Trasování zásobníku: {3}
+
+
+
+
+ Inicializační metoda třídy {0}.{1} vyvolala výjimku. {2}: {3}.
+
+
+
+
+ Při provádění testu došlo k výjimce. Pokud používáte rozšíření třídy TestMethodAttribute, obraťte se na dodavatele. Chybová zpráva: {0}
+
+
+
+
+ Při provádění testu došlo k chybě. Rozšíření nevrátilo žádný výsledek. Pokud používáte rozšíření třídy TestMethodAttribute, obraťte se na dodavatele.
+
+
+
+
+ Metoda {0}.{1} má špatný podpis. Metoda musí být statická, veřejná, nevracet hodnotu a nepřijímat žádné parametry. Pokud navíc v metodě používáte operátor async-await, musí být návratový typ Task.
+
+
+
+
+ Metoda {0}.{1} má špatný podpis. Metoda musí být statická, veřejná, nevracet hodnotu a přijímat jeden parametr typu TestContext. Pokud navíc v metodě používáte operátor async-await, musí být návratový typ Task.
+
+
+
+
+ UTA054: {0}.{1} má neplatný atribut Timeout. Timeout musí být platné celé číslo a nesmí být menší než 0.
+
+
+
+
+ UTA023: {0}: V metodě {1} nejde definovat předdefinovanou vlastnost {2}.
+
+
+
+
+ UTA022: {0}.{1}: Vlastní vlastnost {2} je už definovaná. Použije se hodnota {3}.
+
+
+
+
+ UTA021: {0}: V metodě {1} je definovaná vlastní vlastnost, která je null nebo je prázdná. Vlastní vlastnost musí mít platný název.
+
+
+
+
+ Metoda {0}.{1} neexistuje.
+
+
+
+
+ Pro třídu {0} se nepodařilo najít výchozí konstruktor.
+
+
+
+
+ Nepodařilo se najít vlastnost {0}.TestContext. Chyba:{1}.
+
+
+
+
+ {0}.TestContext má nesprávný typ.
+
+
+
+
+ Metoda {0}.{1} má chybný podpis. Metoda musí být nestatická, veřejná, nevracet hodnotu a nepřijímat žádný parametr. Pokud navíc v metodě používáte operátor async-await, musí být návratový typ Task.
+
+
+
+
+ Nepodařilo se získat typ {0}. Chyba: {1}.
+
+
+
+
+ Testovací metoda {0} se nenašla.
+
+
+
+
+ Trasování ladění:
+
+
+
+
+ Nepovedlo se získat výjimku vyvolanou testovací metodou {0}.{1}.
+
+
+
+
+ V testovací metodě {0}.{1} došlo k výjimce:
+{2}
+
+
+
+
+ {0}. Pokud v testu používáte objekty uživatelského rozhraní, zvažte u projektů pro platformu UPW použití atributu [UITestMethod] místo atributu [TestMethod], aby se test provedl ve vlákně uživatelského rozhraní.
+
+
+
+
+ MSTestAdapterV2
+
+
+
+
+ Neplatné nastavení {0}. Neočekávaný XmlAttribute: {1}.
+
+
+
+
+ Neplatné nastavení {0}. Neočekávaný XmlElement: {1}.
+
+
+
+
+ {0} (datový řádek {1})
+
+
+
+
+ Atribut ExpectedException definovaný u testovací metody {0}.{1} vyvolal během vytváření výjimku.
+{2}
+
+
+
+
+ Testovací metoda {0}.{1} má definovaných více atributů odvozených od atributu ExpectedExceptionBaseAttribute. Povolený je jenom jeden takový atribut.
+
+
+
+
+ Upozornění: Adaptér MSTest V2 nepodporuje soubor testsettings ani vsmdi.
+
+
+
+
+ Zprávy pro TestContext:
+
+
+
+
+ Při volání čisticí metody testu pro třídu {0} došlo k chybě: {1}
+
+
+
+
+ Trasování zásobníku čištění testu
+
+
+
+
+ [MSTest][Discovery][{0}] {1}
+
+
+
+
+ Prováděcí modul MSTest: Je povolená paralelizace testu pro {0} (pracovní procesy: {1}, obor: {2}).
+
+
+
+
+ Pro Obor je zadaná neplatná hodnota {0}. Podporované obory jsou {1}.
+ 'Scope' is a setting name that shouldn't be localized.
+
+
+
+ Pro Pracovní procesy je zadaná neplatná hodnota {0}. Hodnota by měla být nezáporné celé číslo.
+ `Workers` is a setting name that shouldn't be localized.
+
+
+
+ Nepovedlo se zjistit testy ze sestavení {0}. Důvod:{1}
+
+
+
+
+ Parametry můžou mít pouze testovací metody řízené daty. Nechtěli jste použít atribut [DataRow] nebo [DynamicData]?
+
+
+
+
+ Spouštění testu {0} se přerušilo.
+
+
+
+
\ No newline at end of file
diff --git a/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.de.xlf b/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.de.xlf
index f9a8d8366..83c71acf7 100644
--- a/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.de.xlf
+++ b/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.de.xlf
@@ -1,407 +1,343 @@
-
-
-
-
-
-
- Der Test "{0}" hat das Ausführungstimeout überschritten.
-
-
-
-
-
- Das Ausführen von Tests in einer der angegebenen Quellen wird für die ausgewählte Plattform nicht unterstützt.
-
-
-
-
-
- Die TestCleanup-Methode "{0}.{1}" hat eine Ausnahme ausgelöst. {2}: {3}.
-
-
-
-
-
- --- Ende der internen Ausnahmestapelüberwachung ---
-
-
-
-
-
- UTA014: {0}: Es darf nur eine Methode mit dem Attribut 'AssemblyCleanup' innerhalb einer Assembly definiert werden.
-
-
-
-
-
- UTA013: {0}: Es darf nur eine Methode mit dem Attribut 'AssemblyInitialize' innerhalb einer Assembly definiert werden.
-
-
-
-
-
- UTA026: {0}: Es darf nur eine Methode mit dem Attribut 'ClassCleanup' innerhalb einer Klasse definiert werden.
-
-
-
-
-
- UTA025: {0}: Es darf nur eine Methode mit dem Attribut 'ClassInitialize' innerhalb einer Klasse definiert werden.
-
-
-
-
-
- UTA024: {0}: Es darf nur eine Methode mit dem Attribut 'TestCleanup' definiert werden.
-
-
-
-
-
- UTA018: {0}: Es darf nur eine Methode mit dem Attribut 'TestInitialize' definiert werden.
-
-
-
-
-
- Die Initialisierungsmethode '{0}.{1}' hat eine Ausnahme ausgelöst. {2}.
-
-
-
-
-
- Es kann keine Instanz der Klasse '{0}' erstellt werden. Fehler: {1}.
-
-
-
-
-
- Die Eigenschaft 'TestContext' für die Klasse '{0}' kann nicht festgelegt werden. Fehler: {1}.
-
-
-
-
-
- (Fehler beim Abrufen der Meldung für eine Ausnahme vom Typ "{0}" aufgrund einer Ausnahme.)
-
-
-
-
-
- UTA031: Die Klasse '{0}' weist keine gültige Eigenschaft 'TestContext' auf. 'TestContext' muss vom Typ 'TestContext', nicht statisch und öffentlich sein und darf nicht schreibgeschützt sein. Beispiel: 'public TestContext TestContext'.
-
-
-
-
-
- UTA001: Für die nicht öffentliche Klasse '{0}' definiertes Attribut 'TestClass'.
-
-
-
-
-
- Fehler von 'MSTestAdapter' beim Ermitteln von Tests in der Klasse "{0}" der Assembly "{1}". Ursache: {2}.
-
-
-
-
-
- {0}: {1}
-
-
-
-
-
- Fehler beim Laden von Typen aus der Testquelle "{0}". Möglicherweise werden einige oder alle Tests in dieser Quelle nicht ermittelt.
-Fehler: {1}
-
-
-
-
-
- UTA015: Eine generische Methode kann keine Testmethode sein. '{0}.{1}' weist eine ungültige Signatur auf.
-
-
-
-
-
- Der Parameter darf nicht NULL oder leer sein.
-
-
-
-
-
- Der Parameter muss größer als Null sein.
-
-
-
-
-
- Fehler von 'MSTestAdapter' beim Ermitteln von Tests in der Klasse "{0}" der Assembly "{1}". Ursache {2}.
-
-
-
-
-
- Die Datei ist nicht vorhanden: {0}
-
-
-
-
-
- UTA007: Die in der Klasse {0} definierte Methode {1} weist nicht die richtige Signatur auf. Die mit dem [TestMethod]-Attribut markierte Testmethode muss nicht statisch und öffentlich sein, muss den Rückgabetyp "void" aufweisen und darf keine Parameter annehmen. Beispiel: "public void Test.Class1.Test()". Wenn Sie "async-await" in der Testmethode verwenden, muss der Rückgabetyp außerdem "Task" sein. Beispiel: "public async Task Test.Class1.Test2()"
-
-
-
-
-
- "TestContext" darf nicht NULL sein.
-
-
-
-
-
- Fehler bei der Methode "{0}.{1}" für die Assemblybereinigung. Fehlermeldung: {2}. "StackTrace": {3}
-
-
-
-
-
- Die Methode "{0}.{1}" für die Assemblyinitialisierung hat eine Ausnahme ausgelöst. {2}: {3}. Die Ausführung des Tests wird abgebrochen.
-
-
-
-
-
- Fehler bei der Methode "{0}.{1}" für die Klassenbereinigung. Fehlermeldung: {2}. Stapelüberwachung: {3}
-
-
-
-
-
- Die Methode "{0}.{1}" für die Klasseninitialisierung hat eine Ausnahme ausgelöst. {2}: {3}.
-
-
-
-
-
- Während der Ausführung des Tests wurde eine Ausnahme ausgelöst. Wenn Sie eine Extension von "TestMethodAttribute" verwenden, wenden Sie sich bitte an den Anbieter. Fehlermeldung: {0}
-
-
-
-
-
- Fehler beim Ausführen des Tests. Von der Extension wurde kein Ergebnis zurückgegeben. Wenn Sie eine Extension von "TestMethodAttribute" verwenden, wenden Sie sich bitte an den Anbieter.
-
-
-
-
-
- Die Methode "{0}.{1}" weist eine falsche Signatur auf. Die Methode muss statisch und öffentlich sein, gibt keinen Wert zurück und sollte keinen Parameter annehmen. Wenn Sie außerdem in der Methode "async-await" verwenden, muss der Rückgabetyp "Task" sein.
-
-
-
-
-
- Die Methode {0}.{1} weist eine falsche Signatur auf. Die Methode muss statisch und öffentlich sein, gibt keinen Wert zurück und sollte einen einzigen Parameter vom Typ "TestContext" annehmen. Wenn Sie außerdem in der Methode "async-await" verwenden, muss der Rückgabetyp "Task" sein.
-
-
-
-
-
- UTA054: "{0}.{1}" weist ein ungültiges Attribut "Timeout" auf. Das Timeout muss ein gültiger ganzzahliger Wert sein und darf nicht kleiner als 0 sein.
-
-
-
-
-
- UTA023: {0}: Die vordefinierte Eigenschaft "{2}" kann nicht für die Methode "{1}" definiert werden.
-
-
-
-
-
- UTA022: {0}.{1}: Die benutzerdefinierte Eigenschaft "{2}" ist bereits definiert. "{3}" wird als Wert verwendet.
-
-
-
-
-
- UTA021: {0}: Für die Methode "{1}" wurde eine benutzerdefinierte Eigenschaft mit dem Wert NULL oder eine benutzerdefinierte leere Eigenschaft definiert. Die benutzerdefinierte Eigenschaft muss einen gültigen Namen aufweisen.
-
-
-
-
-
- Die Methode "{0}.{1}" ist nicht vorhanden.
-
-
-
-
-
- Der Standardkonstruktor für die Klasse "{0}" kann nicht abgerufen werden.
-
-
-
-
-
- Die Eigenschaft "{0}.TestContext" wurde nicht gefunden. Fehler: {1}.
-
-
-
-
-
- "{0}.TestContext" weist einen falschen Typ auf.
-
-
-
-
-
- Die Methode "{0}.{1}" weist eine falsche Signatur auf. Die Methode muss nicht statisch und öffentlich sein, gibt keinen Wert zurück und sollte keinen Parameter annehmen. Wenn Sie außerdem in der Methode "async-await" verwenden, muss der Rückgabetyp "Task" sein.
-
-
-
-
-
- Der Typ "{0}" kann nicht abgerufen werden. Fehler: {1}.
-
-
-
-
-
- Die Testmethode "{0}" wurde nicht gefunden.
-
-
-
-
-
- Debugablaufverfolgung:
-
-
-
-
-
- Fehler beim Abrufen der von der Testmethode "{0}.{1}" ausgelösten Ausnahme.
-
-
-
-
-
- Die Testmethode "{0}.{1}" hat eine Ausnahme ausgelöst:
-{2}
-
-
-
-
-
- {0}: Erwägen Sie für UWP-Projekte bei Einsatz von UI-Objekten im Test die Verwendung des [UITestMethod]-Attributs anstelle von "[TestMethod]", um den Test im UI-Thread auszuführen.
-
-
-
-
-
- MSTestAdapterV2
-
-
-
-
-
- Ungültige Einstellungen "{0}". Unerwartetes XmlAttribute: "{1}".
-
-
-
-
-
- Ungültige Einstellungen "{0}". Unerwartetes XmlElement: "{1}".
-
-
-
-
-
- {0} (Datenzeile {1})
-
-
-
-
-
- Das für die Testmethode "{0}.{1}" definierte ExpectedException-Attribut hat während der Konstruktion eine Ausnahme ausgelöst.
-{2}
-
-
-
-
-
- Für die Testmethode "{0}.{1}" sind mehrere Attribute definiert, die von ExpectedExceptionBaseAttribute abgeleitet werden. Nur ein einziges solches Attribut ist zulässig.
-
-
-
-
-
- Warnung: Eine TESTSETTINGS-Datei oder eine VSMDI-Datei wird vom MSTest-V2-Adapter nicht unterstützt.
-
-
-
-
-
- TestContext-Meldungen:
-
-
-
-
-
- Fehler beim Aufruf der Testbereinigungsmethode für die Testklasse "{0}": {1}
-
-
-
-
-
- TestCleanup-Stapelüberwachung
-
-
-
-
-
- [MSTest][Discovery][{0}] {1}
-
-
-
-
-
- MSTest-Executor: Testparallelisierung für "{0}" aktiviert (Worker: {1}, Bereich: {2}).
-
-
-
-
-
- Ungültiger Wert "{0}" für "Scope" angegeben. Unterstützte Bereiche: {1}.
- 'Scope' is a setting name that shouldn't be localized.
-
-
-
- Ungültiger Wert "{0}" für "Workers" angegeben. Der Wert muss eine nicht negative Ganzzahl sein.
- `Workers` is a setting name that shouldn't be localized.
-
-
-
- Fehler beim Ermitteln von Tests aus der Assembly "{0}". Ursache:{1}
-
-
-
-
-
- Nur datengesteuerte Testmethoden können Parameter aufweisen. Wollten Sie [DataRow] oder [DynamicData] verwenden?
-
-
-
-
-
- Die Ausführung des Tests "{0}" wurde abgebrochen.
-
-
-
-
-
+
+
+
+
+
+
+ Der Test "{0}" hat das Ausführungstimeout überschritten.
+
+
+
+
+ Das Ausführen von Tests in einer der angegebenen Quellen wird für die ausgewählte Plattform nicht unterstützt.
+
+
+
+
+ Die TestCleanup-Methode "{0}.{1}" hat eine Ausnahme ausgelöst. {2}: {3}.
+
+
+
+
+ --- Ende der internen Ausnahmestapelüberwachung ---
+
+
+
+
+ UTA014: {0}: Es darf nur eine Methode mit dem Attribut 'AssemblyCleanup' innerhalb einer Assembly definiert werden.
+
+
+
+
+ UTA013: {0}: Es darf nur eine Methode mit dem Attribut 'AssemblyInitialize' innerhalb einer Assembly definiert werden.
+
+
+
+
+ UTA026: {0}: Es darf nur eine Methode mit dem Attribut 'ClassCleanup' innerhalb einer Klasse definiert werden.
+
+
+
+
+ UTA025: {0}: Es darf nur eine Methode mit dem Attribut 'ClassInitialize' innerhalb einer Klasse definiert werden.
+
+
+
+
+ UTA024: {0}: Es darf nur eine Methode mit dem Attribut 'TestCleanup' definiert werden.
+
+
+
+
+ UTA018: {0}: Es darf nur eine Methode mit dem Attribut 'TestInitialize' definiert werden.
+
+
+
+
+ Die Initialisierungsmethode '{0}.{1}' hat eine Ausnahme ausgelöst. {2}.
+
+
+
+
+ Es kann keine Instanz der Klasse '{0}' erstellt werden. Fehler: {1}.
+
+
+
+
+ Die Eigenschaft 'TestContext' für die Klasse '{0}' kann nicht festgelegt werden. Fehler: {1}.
+
+
+
+
+ (Fehler beim Abrufen der Meldung für eine Ausnahme vom Typ "{0}" aufgrund einer Ausnahme.)
+
+
+
+
+ UTA031: Die Klasse '{0}' weist keine gültige Eigenschaft 'TestContext' auf. 'TestContext' muss vom Typ 'TestContext', nicht statisch und öffentlich sein und darf nicht schreibgeschützt sein. Beispiel: 'public TestContext TestContext'.
+
+
+
+
+ UTA001: Für die nicht öffentliche Klasse '{0}' definiertes Attribut 'TestClass'.
+
+
+
+
+ Fehler von 'MSTestAdapter' beim Ermitteln von Tests in der Klasse "{0}" der Assembly "{1}". Ursache: {2}.
+
+
+
+
+ {0}: {1}
+
+
+
+
+ Fehler beim Laden von Typen aus der Testquelle "{0}". Möglicherweise werden einige oder alle Tests in dieser Quelle nicht ermittelt.
+Fehler: {1}
+
+
+
+
+ UTA015: Eine generische Methode kann keine Testmethode sein. '{0}.{1}' weist eine ungültige Signatur auf.
+
+
+
+
+ Der Parameter darf nicht NULL oder leer sein.
+
+
+
+
+ Der Parameter muss größer als Null sein.
+
+
+
+
+ Fehler von 'MSTestAdapter' beim Ermitteln von Tests in der Klasse "{0}" der Assembly "{1}". Ursache {2}.
+
+
+
+
+ Die Datei ist nicht vorhanden: {0}
+
+
+
+
+ UTA007: Die in der Klasse {0} definierte Methode {1} weist nicht die richtige Signatur auf. Die mit dem [TestMethod]-Attribut markierte Testmethode muss nicht statisch und öffentlich sein, muss den Rückgabetyp "void" aufweisen und darf keine Parameter annehmen. Beispiel: "public void Test.Class1.Test()". Wenn Sie "async-await" in der Testmethode verwenden, muss der Rückgabetyp außerdem "Task" sein. Beispiel: "public async Task Test.Class1.Test2()"
+
+
+
+
+ "TestContext" darf nicht NULL sein.
+
+
+
+
+ Fehler bei der Methode "{0}.{1}" für die Assemblybereinigung. Fehlermeldung: {2}. "StackTrace": {3}
+
+
+
+
+ Die Methode "{0}.{1}" für die Assemblyinitialisierung hat eine Ausnahme ausgelöst. {2}: {3}. Die Ausführung des Tests wird abgebrochen.
+
+
+
+
+ Fehler bei der Methode "{0}.{1}" für die Klassenbereinigung. Fehlermeldung: {2}. Stapelüberwachung: {3}
+
+
+
+
+ Die Methode "{0}.{1}" für die Klasseninitialisierung hat eine Ausnahme ausgelöst. {2}: {3}.
+
+
+
+
+ Während der Ausführung des Tests wurde eine Ausnahme ausgelöst. Wenn Sie eine Extension von "TestMethodAttribute" verwenden, wenden Sie sich bitte an den Anbieter. Fehlermeldung: {0}
+
+
+
+
+ Fehler beim Ausführen des Tests. Von der Extension wurde kein Ergebnis zurückgegeben. Wenn Sie eine Extension von "TestMethodAttribute" verwenden, wenden Sie sich bitte an den Anbieter.
+
+
+
+
+ Die Methode "{0}.{1}" weist eine falsche Signatur auf. Die Methode muss statisch und öffentlich sein, gibt keinen Wert zurück und sollte keinen Parameter annehmen. Wenn Sie außerdem in der Methode "async-await" verwenden, muss der Rückgabetyp "Task" sein.
+
+
+
+
+ Die Methode {0}.{1} weist eine falsche Signatur auf. Die Methode muss statisch und öffentlich sein, gibt keinen Wert zurück und sollte einen einzigen Parameter vom Typ "TestContext" annehmen. Wenn Sie außerdem in der Methode "async-await" verwenden, muss der Rückgabetyp "Task" sein.
+
+
+
+
+ UTA054: "{0}.{1}" weist ein ungültiges Attribut "Timeout" auf. Das Timeout muss ein gültiger ganzzahliger Wert sein und darf nicht kleiner als 0 sein.
+
+
+
+
+ UTA023: {0}: Die vordefinierte Eigenschaft "{2}" kann nicht für die Methode "{1}" definiert werden.
+
+
+
+
+ UTA022: {0}.{1}: Die benutzerdefinierte Eigenschaft "{2}" ist bereits definiert. "{3}" wird als Wert verwendet.
+
+
+
+
+ UTA021: {0}: Für die Methode "{1}" wurde eine benutzerdefinierte Eigenschaft mit dem Wert NULL oder eine benutzerdefinierte leere Eigenschaft definiert. Die benutzerdefinierte Eigenschaft muss einen gültigen Namen aufweisen.
+
+
+
+
+ Die Methode "{0}.{1}" ist nicht vorhanden.
+
+
+
+
+ Der Standardkonstruktor für die Klasse "{0}" kann nicht abgerufen werden.
+
+
+
+
+ Die Eigenschaft "{0}.TestContext" wurde nicht gefunden. Fehler: {1}.
+
+
+
+
+ "{0}.TestContext" weist einen falschen Typ auf.
+
+
+
+
+ Die Methode "{0}.{1}" weist eine falsche Signatur auf. Die Methode muss nicht statisch und öffentlich sein, gibt keinen Wert zurück und sollte keinen Parameter annehmen. Wenn Sie außerdem in der Methode "async-await" verwenden, muss der Rückgabetyp "Task" sein.
+
+
+
+
+ Der Typ "{0}" kann nicht abgerufen werden. Fehler: {1}.
+
+
+
+
+ Die Testmethode "{0}" wurde nicht gefunden.
+
+
+
+
+ Debugablaufverfolgung:
+
+
+
+
+ Fehler beim Abrufen der von der Testmethode "{0}.{1}" ausgelösten Ausnahme.
+
+
+
+
+ Die Testmethode "{0}.{1}" hat eine Ausnahme ausgelöst:
+{2}
+
+
+
+
+ {0}: Erwägen Sie für UWP-Projekte bei Einsatz von UI-Objekten im Test die Verwendung des [UITestMethod]-Attributs anstelle von "[TestMethod]", um den Test im UI-Thread auszuführen.
+
+
+
+
+ MSTestAdapterV2
+
+
+
+
+ Ungültige Einstellungen "{0}". Unerwartetes XmlAttribute: "{1}".
+
+
+
+
+ Ungültige Einstellungen "{0}". Unerwartetes XmlElement: "{1}".
+
+
+
+
+ {0} (Datenzeile {1})
+
+
+
+
+ Das für die Testmethode "{0}.{1}" definierte ExpectedException-Attribut hat während der Konstruktion eine Ausnahme ausgelöst.
+{2}
+
+
+
+
+ Für die Testmethode "{0}.{1}" sind mehrere Attribute definiert, die von ExpectedExceptionBaseAttribute abgeleitet werden. Nur ein einziges solches Attribut ist zulässig.
+
+
+
+
+ Warnung: Eine TESTSETTINGS-Datei oder eine VSMDI-Datei wird vom MSTest-V2-Adapter nicht unterstützt.
+
+
+
+
+ TestContext-Meldungen:
+
+
+
+
+ Fehler beim Aufruf der Testbereinigungsmethode für die Testklasse "{0}": {1}
+
+
+
+
+ TestCleanup-Stapelüberwachung
+
+
+
+
+ [MSTest][Discovery][{0}] {1}
+
+
+
+
+ MSTest-Executor: Testparallelisierung für "{0}" aktiviert (Worker: {1}, Bereich: {2}).
+
+
+
+
+ Ungültiger Wert "{0}" für "Scope" angegeben. Unterstützte Bereiche: {1}.
+ 'Scope' is a setting name that shouldn't be localized.
+
+
+
+ Ungültiger Wert "{0}" für "Workers" angegeben. Der Wert muss eine nicht negative Ganzzahl sein.
+ `Workers` is a setting name that shouldn't be localized.
+
+
+
+ Fehler beim Ermitteln von Tests aus der Assembly "{0}". Ursache:{1}
+
+
+
+
+ Nur datengesteuerte Testmethoden können Parameter aufweisen. Wollten Sie [DataRow] oder [DynamicData] verwenden?
+
+
+
+
+ Die Ausführung des Tests "{0}" wurde abgebrochen.
+
+
+
+
\ No newline at end of file
diff --git a/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.es.xlf b/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.es.xlf
index 5a64a7069..4dbd9fd9a 100644
--- a/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.es.xlf
+++ b/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.es.xlf
@@ -1,407 +1,343 @@
-
-
-
-
-
-
- La prueba '{0}' superó el tiempo de espera de ejecución.
-
-
-
-
-
- La ejecución de pruebas en las fuentes proporcionadas no se admite para la plataforma seleccionada
-
-
-
-
-
- El método TestCleanup {0}.{1} devolvió una excepción. {2}: {3}.
-
-
-
-
-
- --- Fin del seguimiento de la pila de excepción interna ---
-
-
-
-
-
- UTA014: {0}: No se puede definir más de un método con el atributo AssemblyCleanup dentro de un ensamblado.
-
-
-
-
-
- UTA013: {0}: No se puede definir más de un método con el atributo AssemblyInitialize dentro de un ensamblado.
-
-
-
-
-
- UTA026: {0}: No se puede definir más de un método con el atributo ClassCleanup dentro de una clase.
-
-
-
-
-
- UTA025: {0}: No se puede definir más de un método con el atributo ClassInitialize dentro de una clase.
-
-
-
-
-
- UTA024: {0}: No se puede definir más de un método con el atributo TestCleanup.
-
-
-
-
-
- UTA018: {0}: No se puede definir más de un método con el atributo TestInitialize.
-
-
-
-
-
- El método de inicialización {0}.{1} devolvió una excepción. {2}.
-
-
-
-
-
- No se puede crear una instancia de la clase {0}. Error: {1}.
-
-
-
-
-
- No se puede establecer la propiedad TestContext para la clase {0}. Error: {1}.
-
-
-
-
-
- (No se pudo obtener el mensaje para una excepción del tipo {0} debido a una excepción.)
-
-
-
-
-
- UTA031: la clase {0} no tiene la propiedad TestContext válida. TestContext debe ser de tipo TestContext, debe ser no estática, pública y no debe ser de solo lectura. Por ejemplo: public TestContext TestContext.
-
-
-
-
-
- UTA001: se ha definido el atributo TestClass en la clase no pública {0}
-
-
-
-
-
- MSTestAdapter no detectó pruebas en la clase '{0}' del ensamblado '{1}' porque {2}.
-
-
-
-
-
- {0}: {1}
-
-
-
-
-
- No se pueden cargar tipos del origen de prueba "{0}". Puede que no se detecten algunas o ninguna de las pruebas de este origen.
-Error: {1}
-
-
-
-
-
- UTA015: Un método genérico no puede ser un método de prueba. {0}.{1} tiene una firma no válida
-
-
-
-
-
- El parámetro no debe ser NULL ni estar vacío.
-
-
-
-
-
- El parámetro debe ser mayor que cero.
-
-
-
-
-
- MSTestAdapter no detectó pruebas en la clase '{0}' del ensamblado '{1}'. Motivo: {2}.
-
-
-
-
-
- El archivo no existe: {0}
-
-
-
-
-
- UTA007: El método {1} definido en la clase {0} no tiene una signatura correcta. El método de prueba marcado con el atributo [TestMethod] debe ser no estático, público, con el tipo devuelto void y no debe tomar ningún parámetro. Ejemplo: public void Test.Class1.Test(). Además, si está usando async-await en el método de prueba, el tipo devuelto debe ser Task. Ejemplo: public async Task Test.Class1.Test2()
-
-
-
-
-
- TestContext no será null.
-
-
-
-
-
- Error de método Cleanup de ensamblado {0}.{1}. Mensaje de error: {2}. StackTrace: {3}
-
-
-
-
-
- Excepción método inicialización ensamblado {0}.{1}. {2}: {3}. Anulada ejecución de prueba.
-
-
-
-
-
- Error de método Cleanup de clase {0}.{1}. Mensaje error: {2}. Seguimiento de pila: {3}
-
-
-
-
-
- Excepción del método inicialización clase {0}. {1}. {2}: {3}.
-
-
-
-
-
- Se inició una excepción al ejecutar la prueba. Si usa la extensión de TestMethodAttribute, póngase en contacto con el proveedor. Mensaje de error: {0}
-
-
-
-
-
- No se pudo ejecutar prueba. Extensión no devolvió resultados. Si usa extensión TestMethodAttribute, contacte con el proveedor.
-
-
-
-
-
- Método {0}.{1} tiene firma incorrecta. El método debe ser estático, público, no devolver un valor y no aceptar ningún parámetro. Además, si usa async-esperan en método de tipo de valor devuelto debe ser una tarea.
-
-
-
-
-
- Método {0}.{1} tiene firma incorrecta. El método debe ser estático y público, no devolver ningún valor y debe aceptar un solo parámetro tipo TestContext. Además, si está usando async-await en el método, el tipo devuelto debe ser Task.
-
-
-
-
-
- UTA054: atributo tiempo espera {0}.{1} no válido. Valor tiempo de espera debe ser entero válido y no menor que 0.
-
-
-
-
-
- UTA023: {0}: no se puede definir la propiedad predefinida {2} en el método {1}.
-
-
-
-
-
- UTA022: {0}.{1}: ya definida propiedad personalizada "{2}". Usando "{3}" como valor.
-
-
-
-
-
- UTA021: {0}: se ha definido una propiedad personalizada nula o vacía en el método {1}. La propiedad personalizada debe tener un nombre válido.
-
-
-
-
-
- El método {0}.{1} no existe.
-
-
-
-
-
- No se puede obtener el constructor predeterminado para la clase {0}.
-
-
-
-
-
- No se puede encontrar la propiedad {0}.TestContext. Error:{1}.
-
-
-
-
-
- Tipo {0}.TestContext no es correcto.
-
-
-
-
-
- Método {0}.{1} tiene firma incorrecta. Debe ser un método no estático, público, no devolver ningún valor y no debe aceptar parámetros. Además, si está usando async-await en el método, el tipo devuelto debe ser Task.
-
-
-
-
-
- No se puede obtener el tipo {0}. Error: {1}.
-
-
-
-
-
- No encontrado método prueba {0}.
-
-
-
-
-
- Seguimiento de depuración:
-
-
-
-
-
- No se pudo obtener la excepción iniciada por el método de prueba {0}.{1}.
-
-
-
-
-
- Excepción método de prueba {0}.{1}:
-{2}
-
-
-
-
-
- {0}. En proyectos de UWP, si usa objetos de interfaz de usuario en la prueba, podría usar el atributo [UITestMethod] en lugar de [TestMethod] para ejecutar la prueba en el subproceso de interfaz de usuario.
-
-
-
-
-
- MSTestAdapterV2
-
-
-
-
-
- Valor no válido '{0}'. XmlAttribute no esperado: '{1}'.
-
-
-
-
-
- Valor no válido '{0}'. XmlElement no esperado: '{1}'.
-
-
-
-
-
- {0} (Fila de datos {1})
-
-
-
-
-
- El atributo ExpectedException definido en el método de prueba {0}.{1} inició una excepción durante la construcción.
-{2}
-
-
-
-
-
- El método de prueba {0}.{1} tiene definidos varios atributos derivados de ExpectedExceptionBaseAttribute. Solo se permite uno de estos atributos.
-
-
-
-
-
- Advertencia: No se admite un archivo testsettings o vsmdi con el adaptador de MSTest V2.
-
-
-
-
-
- Mensajes de TestContext:
-
-
-
-
-
- Error al llamar al método Test Cleanup para la clase de prueba {0}: {1}
-
-
-
-
-
- Seguimiento de pila de TestCleanup
-
-
-
-
-
- [MSTest][Discovery][{0}] {1}
-
-
-
-
-
- Ejecutor de MSTest Executor: paralelización de prueba habilitada para {0} (Trabajadores: {1}, Ámbito: {2}).
-
-
-
-
-
- Valor no válido "{0}" especificado para "Ámbito". Los ámbitos admitidos son {1}.
- 'Scope' is a setting name that shouldn't be localized.
-
-
-
- Valor no válido "{0}" especificado para "Trabajadores". El valor debe ser un entero no negativo.
- `Workers` is a setting name that shouldn't be localized.
-
-
-
- No se pudieron detectar pruebas desde el ensamblado {0}. Motivo:{1}
-
-
-
-
-
- Solo los métodos de pruebas controladas por datos pueden tener parámetros. ¿Quería usar [DataRow] o [DynamicData]?
-
-
-
-
-
- Se anuló la ejecución de la prueba "{0}".
-
-
-
-
-
+
+
+
+
+
+
+ La prueba '{0}' superó el tiempo de espera de ejecución.
+
+
+
+
+ La ejecución de pruebas en las fuentes proporcionadas no se admite para la plataforma seleccionada
+
+
+
+
+ El método TestCleanup {0}.{1} devolvió una excepción. {2}: {3}.
+
+
+
+
+ --- Fin del seguimiento de la pila de excepción interna ---
+
+
+
+
+ UTA014: {0}: No se puede definir más de un método con el atributo AssemblyCleanup dentro de un ensamblado.
+
+
+
+
+ UTA013: {0}: No se puede definir más de un método con el atributo AssemblyInitialize dentro de un ensamblado.
+
+
+
+
+ UTA026: {0}: No se puede definir más de un método con el atributo ClassCleanup dentro de una clase.
+
+
+
+
+ UTA025: {0}: No se puede definir más de un método con el atributo ClassInitialize dentro de una clase.
+
+
+
+
+ UTA024: {0}: No se puede definir más de un método con el atributo TestCleanup.
+
+
+
+
+ UTA018: {0}: No se puede definir más de un método con el atributo TestInitialize.
+
+
+
+
+ El método de inicialización {0}.{1} devolvió una excepción. {2}.
+
+
+
+
+ No se puede crear una instancia de la clase {0}. Error: {1}.
+
+
+
+
+ No se puede establecer la propiedad TestContext para la clase {0}. Error: {1}.
+
+
+
+
+ (No se pudo obtener el mensaje para una excepción del tipo {0} debido a una excepción.)
+
+
+
+
+ UTA031: la clase {0} no tiene la propiedad TestContext válida. TestContext debe ser de tipo TestContext, debe ser no estática, pública y no debe ser de solo lectura. Por ejemplo: public TestContext TestContext.
+
+
+
+
+ UTA001: se ha definido el atributo TestClass en la clase no pública {0}
+
+
+
+
+ MSTestAdapter no detectó pruebas en la clase '{0}' del ensamblado '{1}' porque {2}.
+
+
+
+
+ {0}: {1}
+
+
+
+
+ No se pueden cargar tipos del origen de prueba "{0}". Puede que no se detecten algunas o ninguna de las pruebas de este origen.
+Error: {1}
+
+
+
+
+ UTA015: Un método genérico no puede ser un método de prueba. {0}.{1} tiene una firma no válida
+
+
+
+
+ El parámetro no debe ser NULL ni estar vacío.
+
+
+
+
+ El parámetro debe ser mayor que cero.
+
+
+
+
+ MSTestAdapter no detectó pruebas en la clase '{0}' del ensamblado '{1}'. Motivo: {2}.
+
+
+
+
+ El archivo no existe: {0}
+
+
+
+
+ UTA007: El método {1} definido en la clase {0} no tiene una signatura correcta. El método de prueba marcado con el atributo [TestMethod] debe ser no estático, público, con el tipo devuelto void y no debe tomar ningún parámetro. Ejemplo: public void Test.Class1.Test(). Además, si está usando async-await en el método de prueba, el tipo devuelto debe ser Task. Ejemplo: public async Task Test.Class1.Test2()
+
+
+
+
+ TestContext no será null.
+
+
+
+
+ Error de método Cleanup de ensamblado {0}.{1}. Mensaje de error: {2}. StackTrace: {3}
+
+
+
+
+ Excepción método inicialización ensamblado {0}.{1}. {2}: {3}. Anulada ejecución de prueba.
+
+
+
+
+ Error de método Cleanup de clase {0}.{1}. Mensaje error: {2}. Seguimiento de pila: {3}
+
+
+
+
+ Excepción del método inicialización clase {0}. {1}. {2}: {3}.
+
+
+
+
+ Se inició una excepción al ejecutar la prueba. Si usa la extensión de TestMethodAttribute, póngase en contacto con el proveedor. Mensaje de error: {0}
+
+
+
+
+ No se pudo ejecutar prueba. Extensión no devolvió resultados. Si usa extensión TestMethodAttribute, contacte con el proveedor.
+
+
+
+
+ Método {0}.{1} tiene firma incorrecta. El método debe ser estático, público, no devolver un valor y no aceptar ningún parámetro. Además, si usa async-esperan en método de tipo de valor devuelto debe ser una tarea.
+
+
+
+
+ Método {0}.{1} tiene firma incorrecta. El método debe ser estático y público, no devolver ningún valor y debe aceptar un solo parámetro tipo TestContext. Además, si está usando async-await en el método, el tipo devuelto debe ser Task.
+
+
+
+
+ UTA054: atributo tiempo espera {0}.{1} no válido. Valor tiempo de espera debe ser entero válido y no menor que 0.
+
+
+
+
+ UTA023: {0}: no se puede definir la propiedad predefinida {2} en el método {1}.
+
+
+
+
+ UTA022: {0}.{1}: ya definida propiedad personalizada "{2}". Usando "{3}" como valor.
+
+
+
+
+ UTA021: {0}: se ha definido una propiedad personalizada nula o vacía en el método {1}. La propiedad personalizada debe tener un nombre válido.
+
+
+
+
+ El método {0}.{1} no existe.
+
+
+
+
+ No se puede obtener el constructor predeterminado para la clase {0}.
+
+
+
+
+ No se puede encontrar la propiedad {0}.TestContext. Error:{1}.
+
+
+
+
+ Tipo {0}.TestContext no es correcto.
+
+
+
+
+ Método {0}.{1} tiene firma incorrecta. Debe ser un método no estático, público, no devolver ningún valor y no debe aceptar parámetros. Además, si está usando async-await en el método, el tipo devuelto debe ser Task.
+
+
+
+
+ No se puede obtener el tipo {0}. Error: {1}.
+
+
+
+
+ No encontrado método prueba {0}.
+
+
+
+
+ Seguimiento de depuración:
+
+
+
+
+ No se pudo obtener la excepción iniciada por el método de prueba {0}.{1}.
+
+
+
+
+ Excepción método de prueba {0}.{1}:
+{2}
+
+
+
+
+ {0}. En proyectos de UWP, si usa objetos de interfaz de usuario en la prueba, podría usar el atributo [UITestMethod] en lugar de [TestMethod] para ejecutar la prueba en el subproceso de interfaz de usuario.
+
+
+
+
+ MSTestAdapterV2
+
+
+
+
+ Valor no válido '{0}'. XmlAttribute no esperado: '{1}'.
+
+
+
+
+ Valor no válido '{0}'. XmlElement no esperado: '{1}'.
+
+
+
+
+ {0} (Fila de datos {1})
+
+
+
+
+ El atributo ExpectedException definido en el método de prueba {0}.{1} inició una excepción durante la construcción.
+{2}
+
+
+
+
+ El método de prueba {0}.{1} tiene definidos varios atributos derivados de ExpectedExceptionBaseAttribute. Solo se permite uno de estos atributos.
+
+
+
+
+ Advertencia: No se admite un archivo testsettings o vsmdi con el adaptador de MSTest V2.
+
+
+
+
+ Mensajes de TestContext:
+
+
+
+
+ Error al llamar al método Test Cleanup para la clase de prueba {0}: {1}
+
+
+
+
+ Seguimiento de pila de TestCleanup
+
+
+
+
+ [MSTest][Discovery][{0}] {1}
+
+
+
+
+ Ejecutor de MSTest Executor: paralelización de prueba habilitada para {0} (Trabajadores: {1}, Ámbito: {2}).
+
+
+
+
+ Valor no válido "{0}" especificado para "Ámbito". Los ámbitos admitidos son {1}.
+ 'Scope' is a setting name that shouldn't be localized.
+
+
+
+ Valor no válido "{0}" especificado para "Trabajadores". El valor debe ser un entero no negativo.
+ `Workers` is a setting name that shouldn't be localized.
+
+
+
+ No se pudieron detectar pruebas desde el ensamblado {0}. Motivo:{1}
+
+
+
+
+ Solo los métodos de pruebas controladas por datos pueden tener parámetros. ¿Quería usar [DataRow] o [DynamicData]?
+
+
+
+
+ Se anuló la ejecución de la prueba "{0}".
+
+
+
+
\ No newline at end of file
diff --git a/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.fr.xlf b/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.fr.xlf
index 3206d3d4d..e9ebd4931 100644
--- a/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.fr.xlf
+++ b/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.fr.xlf
@@ -1,407 +1,343 @@
-
-
-
-
-
-
- Le test '{0}' a dépassé le délai d'attente de l'exécution.
-
-
-
-
-
- L'exécution de tests dans l'une des sources fournies n'est pas prise en charge pour la plateforme sélectionnée
-
-
-
-
-
- La méthode TestCleanup {0}.{1} a levé une exception. {2}: {3}.
-
-
-
-
-
- --- Fin de la trace de la pile d'exception interne ---
-
-
-
-
-
- UTA014 : {0} : impossible de définir plus d'une méthode avec l'attribut AssemblyCleanup à l'intérieur d'un assembly.
-
-
-
-
-
- UTA013 : {0} : impossible de définir plus d'une méthode avec l'attribut AssemblyInitialize à l'intérieur d'un assembly.
-
-
-
-
-
- UTA026 : {0} : impossible de définir plus d'une méthode avec l'attribut ClassCleanup à l'intérieur d'une classe.
-
-
-
-
-
- UTA025 : {0} : impossible de définir plus d'une méthode avec l'attribut ClassInitialize à l'intérieur d'une classe.
-
-
-
-
-
- UTA024 : {0} : impossible de définir plus d'une méthode avec l'attribut TestCleanup.
-
-
-
-
-
- UTA018 : {0} : impossible de définir plus d'une méthode avec l'attribut TestInitialize.
-
-
-
-
-
- La méthode Initialization {0}.{1} a levé une exception. {2}.
-
-
-
-
-
- Impossible de créer une instance de la classe {0}. Erreur : {1}.
-
-
-
-
-
- Impossible de définir la propriété TestContext pour la classe {0}. Erreur : {1}.
-
-
-
-
-
- (Échec de la réception du message pour une exception de type {0} en raison d'une exception.)
-
-
-
-
-
- UTA031 : la classe {0} ne possède pas une propriété TestContext valide. TestContext doit être de type TestContext, doit être non statique, publique, et ne doit pas être en lecture seule. Par exemple : public TestContext TestContext.
-
-
-
-
-
- UTA001 : attribut TestClass défini sur la classe non publique {0}
-
-
-
-
-
- MSTestAdapter n'a pas découvert de tests dans la classe '{0}' de l'assembly '{1}', car {2}.
-
-
-
-
-
- {0} : {1}
-
-
-
-
-
- Impossible de charger les types à partir de la source de tests '{0}'. Une partie ou l'ensemble des tests de cette source ne peuvent pas être découverts.
-Erreur : {1}
-
-
-
-
-
- UTA015 : une méthode générique ne peut pas être une méthode de test. {0}.{1} a une signature non valide
-
-
-
-
-
- Le paramètre ne doit pas être une valeur Null ou être vide.
-
-
-
-
-
- Le paramètre doit être supérieur à zéro.
-
-
-
-
-
- MSTestAdapter n'a pas découvert de tests dans la classe '{0}' de l'assembly '{1}'. Raison {2}.
-
-
-
-
-
- Fichier inexistant : {0}
-
-
-
-
-
- UTA007 : la méthode {1} définie dans la classe {0} ne dispose pas d'une signature correcte. Une méthode de test marquée avec l'attribut [TestMethod] doit être non statique, doit utiliser void pour return-type et ne doit pas accepter aucun paramètre. Exemple : public void Test.Class1.Test(). En outre, si vous utilisez async-await dans la méthode de test, return-type doit être Task. Exemple : public async Task Test.Class1.Test2()
-
-
-
-
-
- TestContext ne peut pas être null.
-
-
-
-
-
- La méthode Cleanup d'assembly {0}.{1} a échoué. Message d'erreur : {2}. StackTrace : {3}
-
-
-
-
-
- La méthode d'assembly Initialization {0}.{1} a levé une exception. {2} : {3}. Abandon de l'exécution de tests.
-
-
-
-
-
- La méthode de classe Cleanup {0}.{1} a échoué. Message d'erreur : {2}. Trace de la pile : {3}
-
-
-
-
-
- La méthode de classe Initialization {0}.{1} a levé une exception. {2} : {3}.
-
-
-
-
-
- Exception levée pendant l'exécution du test. Si vous utilisez l'extension de TestMethodAttribute, contactez le fournisseur. Message d'erreur : {0}
-
-
-
-
-
- Erreur lors de l'exécution du test. L'extension n'a retourné aucun résultat. Si vous utilisez l'extension de TestMethodAttribute, contactez le fournisseur.
-
-
-
-
-
- La méthode {0}.{1} possède une signature incorrecte. La méthode doit être statique, publique et ne doit retourner aucune valeur ni accepter aucun paramètre. En outre, si vous utilisez async-await dans la méthode, return-type doit être Task.
-
-
-
-
-
- La méthode {0}.{1} possède une signature incorrecte. La méthode doit être statique, publique et ne doit retourner aucune valeur et accepter un seul paramètre de type TestContext. En outre, si vous utilisez async-await dans la méthode, return-type doit être Task.
-
-
-
-
-
- UTA054 : {0}.{1} possède un attribut Timeout non valide. Timeout doit être une valeur entière valide, qui ne doit pas être inférieure à 0.
-
-
-
-
-
- UTA023 : {0} : Impossible de définir la propriété prédéfinie {2} sur la méthode {1}.
-
-
-
-
-
- UTA022 : {0}.{1} : La propriété personnalisée "{2}" est déjà définie. Utilisation de "{3}" comme valeur.
-
-
-
-
-
- UTA021 : {0} : Une propriété null ou vide personnalisée est définie sur la méthode {1}. La propriété personnalisée doit posséder un nom valide.
-
-
-
-
-
- La méthode {0}.{1} n'existe pas.
-
-
-
-
-
- Impossible d'obtenir le constructeur par défaut de la classe {0}.
-
-
-
-
-
- Propriété {0}.TestContext introuvable. Erreur :{1}.
-
-
-
-
-
- {0}.TestContext possède un type incorrect.
-
-
-
-
-
- La méthode {0}.{1} possède une signature incorrecte. La méthode doit être non statique, publique et ne doit retourner aucune valeur ni accepter aucun paramètre. En outre, si vous utilisez async-await dans la méthode, return-type doit être Task.
-
-
-
-
-
- Impossible d'obtenir le type {0}. Erreur : {1}.
-
-
-
-
-
- Méthode de test {0} introuvable.
-
-
-
-
-
- Trace du débogage :
-
-
-
-
-
- Échec de l'obtention de l'exception levée par la méthode de test {0}.{1}.
-
-
-
-
-
- La méthode de test {0}.{1} a levé une exception :
-{2}
-
-
-
-
-
- {0} Pour les projets UWP, si vous utilisez des objets d'IU dans un test, utilisez l'attribut [UITestMethod] à la place de [TestMethod] pour exécuter le test dans le thread d'interface utilisateur.
-
-
-
-
-
- MSTestAdapterV2
-
-
-
-
-
- Paramètres non valides '{0}'. XmlAttribute inattendu : '{1}'.
-
-
-
-
-
- Paramètres non valides '{0}'. XmlElement inattendu : '{1}'.
-
-
-
-
-
- {0} (ligne de données {1})
-
-
-
-
-
- L'attribut ExpectedException défini dans la méthode de test {0}.{1} a levé une exception durant la construction.
-{2}
-
-
-
-
-
- Plusieurs attributs dérivés de ExpectedExceptionBaseAttribute sont définis dans la méthode de test {0}.{1}. Un seul attribut de ce type est autorisé.
-
-
-
-
-
- Avertissement : L'adaptateur MSTest V2 ne prend pas en charge les fichiers testsettings ou vsmdi.
-
-
-
-
-
- Messages TestContext :
-
-
-
-
-
- Erreur lors de l'appel de la méthode Test Cleanup pour la classe de test {0} : {1}
-
-
-
-
-
- Trace de la pile TestCleanup
-
-
-
-
-
- [MSTest][Discovery][{0}] {1}
-
-
-
-
-
- Exécuteur MSTest : parallélisation des tests activée pour {0} (threads de travail : {1}, portée : {2}).
-
-
-
-
-
- Valeur non valide '{0}' spécifiée pour la 'Portée'. Les portées prises en charge sont {1}.
- 'Scope' is a setting name that shouldn't be localized.
-
-
-
- Valeur non valide '{0}' spécifiée pour 'Workers'. La valeur doit être un entier non négatif.
- `Workers` is a setting name that shouldn't be localized.
-
-
-
- Échec de la découverte de tests à partir de l'assembly {0}. Raison :{1}
-
-
-
-
-
- Seules les méthodes de test basées sur les données peuvent avoir des paramètres. Souhaitiez-vous utiliser [DataRow] ou [DynamicData] ?
-
-
-
-
-
- L'exécution du test '{0}' a été abandonnée.
-
-
-
-
-
+
+
+
+
+
+
+ Le test '{0}' a dépassé le délai d'attente de l'exécution.
+
+
+
+
+ L'exécution de tests dans l'une des sources fournies n'est pas prise en charge pour la plateforme sélectionnée
+
+
+
+
+ La méthode TestCleanup {0}.{1} a levé une exception. {2}: {3}.
+
+
+
+
+ --- Fin de la trace de la pile d'exception interne ---
+
+
+
+
+ UTA014 : {0} : impossible de définir plus d'une méthode avec l'attribut AssemblyCleanup à l'intérieur d'un assembly.
+
+
+
+
+ UTA013 : {0} : impossible de définir plus d'une méthode avec l'attribut AssemblyInitialize à l'intérieur d'un assembly.
+
+
+
+
+ UTA026 : {0} : impossible de définir plus d'une méthode avec l'attribut ClassCleanup à l'intérieur d'une classe.
+
+
+
+
+ UTA025 : {0} : impossible de définir plus d'une méthode avec l'attribut ClassInitialize à l'intérieur d'une classe.
+
+
+
+
+ UTA024 : {0} : impossible de définir plus d'une méthode avec l'attribut TestCleanup.
+
+
+
+
+ UTA018 : {0} : impossible de définir plus d'une méthode avec l'attribut TestInitialize.
+
+
+
+
+ La méthode Initialization {0}.{1} a levé une exception. {2}.
+
+
+
+
+ Impossible de créer une instance de la classe {0}. Erreur : {1}.
+
+
+
+
+ Impossible de définir la propriété TestContext pour la classe {0}. Erreur : {1}.
+
+
+
+
+ (Échec de la réception du message pour une exception de type {0} en raison d'une exception.)
+
+
+
+
+ UTA031 : la classe {0} ne possède pas une propriété TestContext valide. TestContext doit être de type TestContext, doit être non statique, publique, et ne doit pas être en lecture seule. Par exemple : public TestContext TestContext.
+
+
+
+
+ UTA001 : attribut TestClass défini sur la classe non publique {0}
+
+
+
+
+ MSTestAdapter n'a pas découvert de tests dans la classe '{0}' de l'assembly '{1}', car {2}.
+
+
+
+
+ {0} : {1}
+
+
+
+
+ Impossible de charger les types à partir de la source de tests '{0}'. Une partie ou l'ensemble des tests de cette source ne peuvent pas être découverts.
+Erreur : {1}
+
+
+
+
+ UTA015 : une méthode générique ne peut pas être une méthode de test. {0}.{1} a une signature non valide
+
+
+
+
+ Le paramètre ne doit pas être une valeur Null ou être vide.
+
+
+
+
+ Le paramètre doit être supérieur à zéro.
+
+
+
+
+ MSTestAdapter n'a pas découvert de tests dans la classe '{0}' de l'assembly '{1}'. Raison {2}.
+
+
+
+
+ Fichier inexistant : {0}
+
+
+
+
+ UTA007 : la méthode {1} définie dans la classe {0} ne dispose pas d'une signature correcte. Une méthode de test marquée avec l'attribut [TestMethod] doit être non statique, doit utiliser void pour return-type et ne doit pas accepter aucun paramètre. Exemple : public void Test.Class1.Test(). En outre, si vous utilisez async-await dans la méthode de test, return-type doit être Task. Exemple : public async Task Test.Class1.Test2()
+
+
+
+
+ TestContext ne peut pas être null.
+
+
+
+
+ La méthode Cleanup d'assembly {0}.{1} a échoué. Message d'erreur : {2}. StackTrace : {3}
+
+
+
+
+ La méthode d'assembly Initialization {0}.{1} a levé une exception. {2} : {3}. Abandon de l'exécution de tests.
+
+
+
+
+ La méthode de classe Cleanup {0}.{1} a échoué. Message d'erreur : {2}. Trace de la pile : {3}
+
+
+
+
+ La méthode de classe Initialization {0}.{1} a levé une exception. {2} : {3}.
+
+
+
+
+ Exception levée pendant l'exécution du test. Si vous utilisez l'extension de TestMethodAttribute, contactez le fournisseur. Message d'erreur : {0}
+
+
+
+
+ Erreur lors de l'exécution du test. L'extension n'a retourné aucun résultat. Si vous utilisez l'extension de TestMethodAttribute, contactez le fournisseur.
+
+
+
+
+ La méthode {0}.{1} possède une signature incorrecte. La méthode doit être statique, publique et ne doit retourner aucune valeur ni accepter aucun paramètre. En outre, si vous utilisez async-await dans la méthode, return-type doit être Task.
+
+
+
+
+ La méthode {0}.{1} possède une signature incorrecte. La méthode doit être statique, publique et ne doit retourner aucune valeur et accepter un seul paramètre de type TestContext. En outre, si vous utilisez async-await dans la méthode, return-type doit être Task.
+
+
+
+
+ UTA054 : {0}.{1} possède un attribut Timeout non valide. Timeout doit être une valeur entière valide, qui ne doit pas être inférieure à 0.
+
+
+
+
+ UTA023 : {0} : Impossible de définir la propriété prédéfinie {2} sur la méthode {1}.
+
+
+
+
+ UTA022 : {0}.{1} : La propriété personnalisée "{2}" est déjà définie. Utilisation de "{3}" comme valeur.
+
+
+
+
+ UTA021 : {0} : Une propriété null ou vide personnalisée est définie sur la méthode {1}. La propriété personnalisée doit posséder un nom valide.
+
+
+
+
+ La méthode {0}.{1} n'existe pas.
+
+
+
+
+ Impossible d'obtenir le constructeur par défaut de la classe {0}.
+
+
+
+
+ Propriété {0}.TestContext introuvable. Erreur :{1}.
+
+
+
+
+ {0}.TestContext possède un type incorrect.
+
+
+
+
+ La méthode {0}.{1} possède une signature incorrecte. La méthode doit être non statique, publique et ne doit retourner aucune valeur ni accepter aucun paramètre. En outre, si vous utilisez async-await dans la méthode, return-type doit être Task.
+
+
+
+
+ Impossible d'obtenir le type {0}. Erreur : {1}.
+
+
+
+
+ Méthode de test {0} introuvable.
+
+
+
+
+ Trace du débogage :
+
+
+
+
+ Échec de l'obtention de l'exception levée par la méthode de test {0}.{1}.
+
+
+
+
+ La méthode de test {0}.{1} a levé une exception :
+{2}
+
+
+
+
+ {0} Pour les projets UWP, si vous utilisez des objets d'IU dans un test, utilisez l'attribut [UITestMethod] à la place de [TestMethod] pour exécuter le test dans le thread d'interface utilisateur.
+
+
+
+
+ MSTestAdapterV2
+
+
+
+
+ Paramètres non valides '{0}'. XmlAttribute inattendu : '{1}'.
+
+
+
+
+ Paramètres non valides '{0}'. XmlElement inattendu : '{1}'.
+
+
+
+
+ {0} (ligne de données {1})
+
+
+
+
+ L'attribut ExpectedException défini dans la méthode de test {0}.{1} a levé une exception durant la construction.
+{2}
+
+
+
+
+ Plusieurs attributs dérivés de ExpectedExceptionBaseAttribute sont définis dans la méthode de test {0}.{1}. Un seul attribut de ce type est autorisé.
+
+
+
+
+ Avertissement : L'adaptateur MSTest V2 ne prend pas en charge les fichiers testsettings ou vsmdi.
+
+
+
+
+ Messages TestContext :
+
+
+
+
+ Erreur lors de l'appel de la méthode Test Cleanup pour la classe de test {0} : {1}
+
+
+
+
+ Trace de la pile TestCleanup
+
+
+
+
+ [MSTest][Discovery][{0}] {1}
+
+
+
+
+ Exécuteur MSTest : parallélisation des tests activée pour {0} (threads de travail : {1}, portée : {2}).
+
+
+
+
+ Valeur non valide '{0}' spécifiée pour la 'Portée'. Les portées prises en charge sont {1}.
+ 'Scope' is a setting name that shouldn't be localized.
+
+
+
+ Valeur non valide '{0}' spécifiée pour 'Workers'. La valeur doit être un entier non négatif.
+ `Workers` is a setting name that shouldn't be localized.
+
+
+
+ Échec de la découverte de tests à partir de l'assembly {0}. Raison :{1}
+
+
+
+
+ Seules les méthodes de test basées sur les données peuvent avoir des paramètres. Souhaitiez-vous utiliser [DataRow] ou [DynamicData] ?
+
+
+
+
+ L'exécution du test '{0}' a été abandonnée.
+
+
+
+
\ No newline at end of file
diff --git a/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.it.xlf b/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.it.xlf
index 670b7f1e3..e34a99bec 100644
--- a/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.it.xlf
+++ b/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.it.xlf
@@ -1,407 +1,343 @@
-
-
-
-
-
-
- È stato superato il periodo di timeout per l'esecuzione del test '{0}'.
-
-
-
-
-
- L'esecuzione di test in una delle origini specificate non è supportata per la piattaforma selezionata
-
-
-
-
-
- Il metodo TestCleanup {0}.{1} ha generato un'eccezione. {2}: {3}.
-
-
-
-
-
- --- Fine dell'analisi dello stack dell'eccezione interna ---
-
-
-
-
-
- UTA014: {0}: non è possibile definire più di un metodo con l'attributo AssemblyCleanup all'interno di un assembly.
-
-
-
-
-
- UTA013: {0}: non è possibile definire più di un metodo con l'attributo AssemblyInitialize all'interno di un assembly.
-
-
-
-
-
- UTA026: {0}: non è possibile definire più di un metodo con l'attributo ClassCleanup all'interno di una classe.
-
-
-
-
-
- UTA025: {0}: non è possibile definire più di un metodo con l'attributo ClassInitialize all'interno di una classe.
-
-
-
-
-
- UTA024: {0}: non è possibile definire più di un metodo con l'attributo TestCleanup.
-
-
-
-
-
- UTA018: {0}: non è possibile definire più di un metodo con l'attributo TestInitialize.
-
-
-
-
-
- Il metodo di inizializzazione {0}.{1} ha generato un'eccezione. {2}.
-
-
-
-
-
- Non è possibile creare un'istanza della classe {0}. Errore: {1}.
-
-
-
-
-
- Non è possibile impostare la proprietà TestContext per la classe {0}. Errore: {1}.
-
-
-
-
-
- Non è stato possibile ottenere il messaggio per un'eccezione di tipo {0} a causa di un'eccezione.
-
-
-
-
-
- UTA031: la classe {0} non contiene una proprietà TestContext valida. TestContext deve essere una proprietà di tipo TestContext, non statica, pubblica e non di sola lettura. Esempio: public TestContext TestContext.
-
-
-
-
-
- UTA001: è stato definito l'attributo TestClass per la classe non pubblica {0}
-
-
-
-
-
- MSTestAdapter non è riuscito a individuare test nella classe '{0}' dell'assembly '{1}' perché {2}.
-
-
-
-
-
- {0}: {1}
-
-
-
-
-
- Non è possibile caricare i tipi dall'origine test '{0}'. È possibile che alcuni o tutti i test non siano stati individuati in questa origine.
-Errore: {1}
-
-
-
-
-
- UTA015: un metodo generico non può essere un metodo di test. La firma di {0}.{1} non è valida
-
-
-
-
-
- Il parametro non deve essere vuoto o Null.
-
-
-
-
-
- Il parametro deve essere maggiore di zero.
-
-
-
-
-
- MSTestAdapter non è riuscito a individuare test nella classe '{0}' dell'assembly '{1}'. Motivo: {2}.
-
-
-
-
-
- Il file {0} non esiste
-
-
-
-
-
- UTA007: la firma del metodo {1} definito nella classe {0} non è corretta. Il metodo di test contrassegnato con l'attributo [TestMethod] deve essere pubblico e non statico, non deve accettare parametri e deve includere un tipo restituito void. Esempio: public void Test.Class1.Test(). Se inoltre nel metodo di test si usa async-await, il tipo restituito deve essere Task. Esempio: public async Task Test.Class1.Test2()
-
-
-
-
-
- TestContext non può essere Null.
-
-
-
-
-
- Il metodo di pulizia assembly {0}.{1} non è riuscito. Messaggio di errore: {2}. Analisi dello stack: {3}
-
-
-
-
-
- Il metodo di inizializzazione assembly {0}.{1} ha generato un'eccezione. {2}: {3}. L'esecuzione del test verrà interrotta.
-
-
-
-
-
- Il metodo di pulizia classi {0}.{1} non è riuscito. Messaggio di errore: {2}. Analisi dello stack: {3}
-
-
-
-
-
- Il metodo di inizializzazione classi {0}.{1} ha generato un'eccezione. {2}: {3}.
-
-
-
-
-
- È stata generata un'eccezione durante l'esecuzione del test. Se si usa l'estensione di TestMethodAttribute, contattare il fornitore. Messaggio di errore: {0}
-
-
-
-
-
- Si è verificato un errore durante l'esecuzione del test. L'estensione non ha restituito alcun risultato. Se si usa l'estensione di TestMethodAttribute, contattare il fornitore.
-
-
-
-
-
- La firma del metodo {0}.{1} non è corretta. Il metodo deve essere statico e pubblico, non deve restituire un valore né accettare parametri. Se inoltre si usa async-await nel metodo di test, il tipo restituito deve essere Task.
-
-
-
-
-
- La firma del metodo {0}.{1} non è corretta. Il metodo deve essere statico e pubblico, non deve restituire un valore e deve accettare un singolo parametro di tipo TestContext. Se inoltre si usa async-await nel metodo di test, il tipo restituito deve essere Task.
-
-
-
-
-
- UTA054: l'attributo Timeout di {0}.{1} non è valido. Il timeout deve essere un valore intero valido non minore di 0.
-
-
-
-
-
- UTA023: {0}: non è possibile definire la proprietà predefinita {2} per il metodo {1}.
-
-
-
-
-
- UTA022: {0}.{1}: la proprietà personalizzata "{2}" dell'agente è già definita. Verrà usato il valore "{3}".
-
-
-
-
-
- UTA021: {0}: per il metodo {1} è stata definita una proprietà personalizzata Null o vuota. Specificare un nome valido per la proprietà personalizzata.
-
-
-
-
-
- Il metodo {0}.{1} non esiste.
-
-
-
-
-
- Non è possibile ottenere il costruttore predefinito per la classe {0}.
-
-
-
-
-
- La proprietà {0}.TestContext non è stata trovata. Errore: {1}.
-
-
-
-
-
- Il tipo di {0}.TestContext non è corretto.
-
-
-
-
-
- La firma del metodo {0}.{1} non è corretta. Il metodo deve essere non statico e pubblico, non deve restituire un valore né accettare parametri. Se inoltre si usa async-await nel metodo di test, il tipo restituito deve essere Task.
-
-
-
-
-
- Non è possibile ottenere il tipo {0}. Errore: {1}.
-
-
-
-
-
- Il metodo di test {0} non è stato trovato.
-
-
-
-
-
- Traccia di debug:
-
-
-
-
-
- Non è stato possibile ottenere l'eccezione generata dal metodo di test {0}.{1}.
-
-
-
-
-
- Il metodo di test {0}.{1} ha generato un'eccezione:
-{2}
-
-
-
-
-
- {0}. Se, per i progetti della piattaforma UWP, nel test si usano oggetti dell'interfaccia utente, provare a specificare l'attributo [UITestMethod] invece di [TestMethod] per eseguire il test nel thread di UI.
-
-
-
-
-
- MSTestAdapterV2
-
-
-
-
-
- Le impostazioni '{0}' non sono valide. Elemento XmlAttribute imprevisto: '{1}'.
-
-
-
-
-
- Le impostazioni '{0}' non sono valide. Elemento XmlElement imprevisto: '{1}'.
-
-
-
-
-
- {0} (riga dati {1})
-
-
-
-
-
- L'attributo ExpectedException definito nel metodo di test {0}.{1} ha generato un'eccezione durante la costruzione.
-{2}
-
-
-
-
-
- Il metodo di test {0}.{1} contiene più attributi derivati dall'elemento ExpectedExceptionBaseAttribute definito per esso. È consentito solo uno di tali attributi.
-
-
-
-
-
- Avviso: con l'adattatore MSTest V2 non è possibile usare un file testsettings o un file vsmdi.
-
-
-
-
-
- Messaggi di TestContext:
-
-
-
-
-
- Si è verificato un errore durante la chiamata del metodo TestCleanup per la classe di test {0}: {1}
-
-
-
-
-
- Analisi dello stato di TestCleanup
-
-
-
-
-
- [MSTest][Individuazione][{0}] {1}
-
-
-
-
-
- Executor MSTest: Parallelizzazione test abilitata per {0} (Workers: {1}. Scope: {2}).
-
-
-
-
-
- Il valore '{0}', specificato per 'Scope', non è valido. I valori supportati per Scope sono {1}.
- 'Scope' is a setting name that shouldn't be localized.
-
-
-
- Il valore '{0}', specificato per 'Workers', non è valido. Il valore deve essere un numero intero non negativo.
- `Workers` is a setting name that shouldn't be localized.
-
-
-
- Non è stato possibile individuare i test dall'assembly {0}. Motivo: {1}
-
-
-
-
-
- Solo i metodi di test basati sui dati possono includere parametri. Si intendeva usare [DataRow] o [DynamicData]?
-
-
-
-
-
- L'esecuzione del test '{0}' è stata interrotta.
-
-
-
-
-
+
+
+
+
+
+
+ È stato superato il periodo di timeout per l'esecuzione del test '{0}'.
+
+
+
+
+ L'esecuzione di test in una delle origini specificate non è supportata per la piattaforma selezionata
+
+
+
+
+ Il metodo TestCleanup {0}.{1} ha generato un'eccezione. {2}: {3}.
+
+
+
+
+ --- Fine dell'analisi dello stack dell'eccezione interna ---
+
+
+
+
+ UTA014: {0}: non è possibile definire più di un metodo con l'attributo AssemblyCleanup all'interno di un assembly.
+
+
+
+
+ UTA013: {0}: non è possibile definire più di un metodo con l'attributo AssemblyInitialize all'interno di un assembly.
+
+
+
+
+ UTA026: {0}: non è possibile definire più di un metodo con l'attributo ClassCleanup all'interno di una classe.
+
+
+
+
+ UTA025: {0}: non è possibile definire più di un metodo con l'attributo ClassInitialize all'interno di una classe.
+
+
+
+
+ UTA024: {0}: non è possibile definire più di un metodo con l'attributo TestCleanup.
+
+
+
+
+ UTA018: {0}: non è possibile definire più di un metodo con l'attributo TestInitialize.
+
+
+
+
+ Il metodo di inizializzazione {0}.{1} ha generato un'eccezione. {2}.
+
+
+
+
+ Non è possibile creare un'istanza della classe {0}. Errore: {1}.
+
+
+
+
+ Non è possibile impostare la proprietà TestContext per la classe {0}. Errore: {1}.
+
+
+
+
+ Non è stato possibile ottenere il messaggio per un'eccezione di tipo {0} a causa di un'eccezione.
+
+
+
+
+ UTA031: la classe {0} non contiene una proprietà TestContext valida. TestContext deve essere una proprietà di tipo TestContext, non statica, pubblica e non di sola lettura. Esempio: public TestContext TestContext.
+
+
+
+
+ UTA001: è stato definito l'attributo TestClass per la classe non pubblica {0}
+
+
+
+
+ MSTestAdapter non è riuscito a individuare test nella classe '{0}' dell'assembly '{1}' perché {2}.
+
+
+
+
+ {0}: {1}
+
+
+
+
+ Non è possibile caricare i tipi dall'origine test '{0}'. È possibile che alcuni o tutti i test non siano stati individuati in questa origine.
+Errore: {1}
+
+
+
+
+ UTA015: un metodo generico non può essere un metodo di test. La firma di {0}.{1} non è valida
+
+
+
+
+ Il parametro non deve essere vuoto o Null.
+
+
+
+
+ Il parametro deve essere maggiore di zero.
+
+
+
+
+ MSTestAdapter non è riuscito a individuare test nella classe '{0}' dell'assembly '{1}'. Motivo: {2}.
+
+
+
+
+ Il file {0} non esiste
+
+
+
+
+ UTA007: la firma del metodo {1} definito nella classe {0} non è corretta. Il metodo di test contrassegnato con l'attributo [TestMethod] deve essere pubblico e non statico, non deve accettare parametri e deve includere un tipo restituito void. Esempio: public void Test.Class1.Test(). Se inoltre nel metodo di test si usa async-await, il tipo restituito deve essere Task. Esempio: public async Task Test.Class1.Test2()
+
+
+
+
+ TestContext non può essere Null.
+
+
+
+
+ Il metodo di pulizia assembly {0}.{1} non è riuscito. Messaggio di errore: {2}. Analisi dello stack: {3}
+
+
+
+
+ Il metodo di inizializzazione assembly {0}.{1} ha generato un'eccezione. {2}: {3}. L'esecuzione del test verrà interrotta.
+
+
+
+
+ Il metodo di pulizia classi {0}.{1} non è riuscito. Messaggio di errore: {2}. Analisi dello stack: {3}
+
+
+
+
+ Il metodo di inizializzazione classi {0}.{1} ha generato un'eccezione. {2}: {3}.
+
+
+
+
+ È stata generata un'eccezione durante l'esecuzione del test. Se si usa l'estensione di TestMethodAttribute, contattare il fornitore. Messaggio di errore: {0}
+
+
+
+
+ Si è verificato un errore durante l'esecuzione del test. L'estensione non ha restituito alcun risultato. Se si usa l'estensione di TestMethodAttribute, contattare il fornitore.
+
+
+
+
+ La firma del metodo {0}.{1} non è corretta. Il metodo deve essere statico e pubblico, non deve restituire un valore né accettare parametri. Se inoltre si usa async-await nel metodo di test, il tipo restituito deve essere Task.
+
+
+
+
+ La firma del metodo {0}.{1} non è corretta. Il metodo deve essere statico e pubblico, non deve restituire un valore e deve accettare un singolo parametro di tipo TestContext. Se inoltre si usa async-await nel metodo di test, il tipo restituito deve essere Task.
+
+
+
+
+ UTA054: l'attributo Timeout di {0}.{1} non è valido. Il timeout deve essere un valore intero valido non minore di 0.
+
+
+
+
+ UTA023: {0}: non è possibile definire la proprietà predefinita {2} per il metodo {1}.
+
+
+
+
+ UTA022: {0}.{1}: la proprietà personalizzata "{2}" dell'agente è già definita. Verrà usato il valore "{3}".
+
+
+
+
+ UTA021: {0}: per il metodo {1} è stata definita una proprietà personalizzata Null o vuota. Specificare un nome valido per la proprietà personalizzata.
+
+
+
+
+ Il metodo {0}.{1} non esiste.
+
+
+
+
+ Non è possibile ottenere il costruttore predefinito per la classe {0}.
+
+
+
+
+ La proprietà {0}.TestContext non è stata trovata. Errore: {1}.
+
+
+
+
+ Il tipo di {0}.TestContext non è corretto.
+
+
+
+
+ La firma del metodo {0}.{1} non è corretta. Il metodo deve essere non statico e pubblico, non deve restituire un valore né accettare parametri. Se inoltre si usa async-await nel metodo di test, il tipo restituito deve essere Task.
+
+
+
+
+ Non è possibile ottenere il tipo {0}. Errore: {1}.
+
+
+
+
+ Il metodo di test {0} non è stato trovato.
+
+
+
+
+ Traccia di debug:
+
+
+
+
+ Non è stato possibile ottenere l'eccezione generata dal metodo di test {0}.{1}.
+
+
+
+
+ Il metodo di test {0}.{1} ha generato un'eccezione:
+{2}
+
+
+
+
+ {0}. Se, per i progetti della piattaforma UWP, nel test si usano oggetti dell'interfaccia utente, provare a specificare l'attributo [UITestMethod] invece di [TestMethod] per eseguire il test nel thread di UI.
+
+
+
+
+ MSTestAdapterV2
+
+
+
+
+ Le impostazioni '{0}' non sono valide. Elemento XmlAttribute imprevisto: '{1}'.
+
+
+
+
+ Le impostazioni '{0}' non sono valide. Elemento XmlElement imprevisto: '{1}'.
+
+
+
+
+ {0} (riga dati {1})
+
+
+
+
+ L'attributo ExpectedException definito nel metodo di test {0}.{1} ha generato un'eccezione durante la costruzione.
+{2}
+
+
+
+
+ Il metodo di test {0}.{1} contiene più attributi derivati dall'elemento ExpectedExceptionBaseAttribute definito per esso. È consentito solo uno di tali attributi.
+
+
+
+
+ Avviso: con l'adattatore MSTest V2 non è possibile usare un file testsettings o un file vsmdi.
+
+
+
+
+ Messaggi di TestContext:
+
+
+
+
+ Si è verificato un errore durante la chiamata del metodo TestCleanup per la classe di test {0}: {1}
+
+
+
+
+ Analisi dello stato di TestCleanup
+
+
+
+
+ [MSTest][Individuazione][{0}] {1}
+
+
+
+
+ Executor MSTest: Parallelizzazione test abilitata per {0} (Workers: {1}. Scope: {2}).
+
+
+
+
+ Il valore '{0}', specificato per 'Scope', non è valido. I valori supportati per Scope sono {1}.
+ 'Scope' is a setting name that shouldn't be localized.
+
+
+
+ Il valore '{0}', specificato per 'Workers', non è valido. Il valore deve essere un numero intero non negativo.
+ `Workers` is a setting name that shouldn't be localized.
+
+
+
+ Non è stato possibile individuare i test dall'assembly {0}. Motivo: {1}
+
+
+
+
+ Solo i metodi di test basati sui dati possono includere parametri. Si intendeva usare [DataRow] o [DynamicData]?
+
+
+
+
+ L'esecuzione del test '{0}' è stata interrotta.
+
+
+
+
\ No newline at end of file
diff --git a/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.ja.xlf b/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.ja.xlf
index c0d288509..39c7249ab 100644
--- a/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.ja.xlf
+++ b/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.ja.xlf
@@ -1,407 +1,343 @@
-
-
-
-
-
-
- テスト '{0}' は実行タイムアウトを超えました。
-
-
-
-
-
- 指定されたソースのいずれかでのテストの実行は、選択されたプラットフォームでサポートされていません
-
-
-
-
-
- TestCleanup メソッド {0}.{1} は例外をスローしました。{2}: {3}。
-
-
-
-
-
- --- 内部例外スタック トレースの終わり ---
-
-
-
-
-
- UTA014: {0}: 1 つのアセンブリ内で、AssemblyCleanup 属性を伴う 2 つ以上のメソッドを定義することはできません。
-
-
-
-
-
- UTA013: {0}: 1 つのアセンブリ内で、AssemblyInitialize 属性を伴う 2 つ以上のメソッドを定義することはできません。
-
-
-
-
-
- UTA026: {0}: 1 つのクラス内で、ClassCleanup 属性を伴う 2 つ以上のメソッドを定義することはできません。
-
-
-
-
-
- UTA025: {0}: 1 つのクラス内で、ClassInitialize 属性を伴う 2 つ以上のメソッドを定義することはできません。
-
-
-
-
-
- UTA024: {0}: TestCleanup 属性を伴う 2 つ以上のメソッドを定義することはできません。
-
-
-
-
-
- UTA018: {0}: TestInitialize 属性を伴う 2 つ以上のメソッドを定義することはできません。
-
-
-
-
-
- 初期化メソッド {0}.{1} は例外をスローしました。{2}。
-
-
-
-
-
- クラス {0} のインスタンスを作成できません。エラー: {1}。
-
-
-
-
-
- クラス {0} の TestContext プロパティを設定できません。エラー: {1}。
-
-
-
-
-
- (例外が発生したため、型 {0} の例外のメッセージを取得できませんでした。)
-
-
-
-
-
- UTA031: クラス {0} は有効な TestContext プロパティを含んでいません。TestContext は、型 TestContext でなければなりません。また、non-static および public である必要があり、読み取り専用に指定することはできません。例: public TestContext TestContext。
-
-
-
-
-
- UTA001: TestClass 属性がパブリックでないクラス {0} で定義されています
-
-
-
-
-
- MSTestAdapter でアセンブリ '{1}' のクラス '{0}' にテストが見つかりませんでした。理由 {2}。
-
-
-
-
-
- {0}: {1}
-
-
-
-
-
- テスト ソース '{0}' から型を読み込むことができません。このソース内の一部またはすべてのテストが見つからない可能性があります。
-エラー: {1}
-
-
-
-
-
- UTA015: ジェネリック メソッドがテスト メソッドになることはできません。{0}.{1} のシグネチャは無効です
-
-
-
-
-
- パラメーターを null または空にすることはできません。
-
-
-
-
-
- パラメーターはゼロよりも大きい必要があります。
-
-
-
-
-
- MSTestAdapter でアセンブリ '{1}' のクラス '{0}' にテストが見つかりませんでした。理由 {2}。
-
-
-
-
-
- ファイルが存在しません: {0}
-
-
-
-
-
- UTA007: クラス {0} で定義されたメソッド {1} は正しいシグネチャを含んでいません。[TestMethod] 属性を伴って設定されたテスト メソッドは non-static、public にする必要があり、戻り値の型は void でなければなりません。また、パラメーターを受け取ることはできません。例: public void Test.Class1.Test()。また、テスト メソッドで async-await を使用する場合、戻り値の型は Task にする必要があります。例: public async Task Test.Class1.Test2()
-
-
-
-
-
- TestContext を Null にすることはできません。
-
-
-
-
-
- アセンブリ クリーンアップ メソッド {0}.{1} に失敗しました。エラー メッセージ: {2}。スタック トレース: {3}
-
-
-
-
-
- アセンブリ初期化メソッド {0}.{1} は例外をスローしました。{2}: {3}。テストの実行を中止しています。
-
-
-
-
-
- クラス クリーンアップ メソッド {0}.{1} に失敗しました。エラー メッセージ: {2}。スタック トレース: {3}
-
-
-
-
-
- クラス初期化メソッド {0}.{1} は例外をスローしました。{2}: {3}。
-
-
-
-
-
- テストの実行中に例外がスローされました。TestMethodAttribute の拡張クラスを使用している場合は、ベンダーに連絡してください。エラー メッセージ: {0}
-
-
-
-
-
- テストの実行中にエラーが発生しました。拡張から結果が返されませんでした。TestMethodAttribute の拡張クラスを使用している場合は、ベンダーに連絡してください。
-
-
-
-
-
- メソッド {0}.{1} は不適切なシグネチャを含んでいます。メソッドは static および public である必要があり、値を返しません。また、パラメーターを受け取ることはできません。さらに、メソッドで async-await を使用している場合、戻り値の型は Task である必要があります。
-
-
-
-
-
- メソッド {0}.{1} は不適切なシグネチャを含んでいます。メソッドは static および public である必要があり、値を返しません。また、TestContext 型の 1 つのパラメーターを受け取る必要があります。さらに、メソッドで async-await を使用している場合、戻り値の型は Task である必要があります。
-
-
-
-
-
- UTA054: {0}.{1} は無効な Timeout 属性を含んでいます。タイムアウトは有効な整数値でなければなりません。0 よりも小さい値にすることはできません。
-
-
-
-
-
- UTA023: {0}: メソッド {1} 上の以前に定義されたプロパティ {2} を定義することはできません。
-
-
-
-
-
- UTA022: {0}.{1}: カスタム プロパティ "{2}" は既に定義されています。"{3}" を値として使用しています。
-
-
-
-
-
- UTA021: {0}: Null または空のカスタム プロパティが、メソッド {1} で定義されています。カスタム プロパティには有効な名前を指定しなければなりません。
-
-
-
-
-
- メソッド {0}.{1} は存在しません。
-
-
-
-
-
- クラス {0} の既定コンストラクターを取得できません。
-
-
-
-
-
- プロパティ {0}.TestContext が見つかりません。エラー: {1}。
-
-
-
-
-
- {0}.TestContext は不適切な型を含んでいます。
-
-
-
-
-
- メソッド {0}.{1} は不適切なシグネチャを含んでいます。メソッドは non-static および public である必要があり、値を返しません。また、パラメーターを受け取ることはできません。さらに、メソッドで async-await を使用している場合、戻り値の型は Task である必要があります。
-
-
-
-
-
- 型 {0} を取得できません。エラー: {1}。
-
-
-
-
-
- テスト メソッド {0} が見つかりませんでした。
-
-
-
-
-
- デバッグ トレース:
-
-
-
-
-
- テスト メソッド {0}.{1} によってスローされた例外を取得できませんでした。
-
-
-
-
-
- テスト メソッド {0}.{1} が例外をスローしました:
-{2}
-
-
-
-
-
- {0} UWP プロジェクトについて、テスト内で UI オブジェクトを使用している場合は、[TestMethod] の代わりに [UITestMethod] 属性を使用して UI スレッド内でテストを実行することを検討してください。
-
-
-
-
-
- MSTestAdapterV2
-
-
-
-
-
- 設定 '{0}' は無効です。予期しない XmlAttribute: '{1}'。
-
-
-
-
-
- 設定 '{0}' は無効です。予期しない XmlElement: '{1}'。
-
-
-
-
-
- {0} (データ行 {1})
-
-
-
-
-
- テスト メソッド {0}.{1} に定義されている ExpectedException 属性が、作成中に例外をスローしました。
-{2}
-
-
-
-
-
- テスト メソッド {0}.{1} には、ExpectedExceptionBaseAttribute から派生した属性が複数定義されています。このような属性は 1 つしか許可されません。
-
-
-
-
-
- 警告: testsettings ファイル、vsmdi ファイルは MSTest V2 アダプターではサポートされていません。
-
-
-
-
-
- TestContext メッセージ:
-
-
-
-
-
- テスト クラス {0} のテスト クリーンアップ メソッドの呼び出しでエラーが発生しました: {1}
-
-
-
-
-
- TestCleanup スタック トレース
-
-
-
-
-
- [MSTest][Discovery][{0}] {1}
-
-
-
-
-
- MSTest 実行プログラム: {0} でテスト並列処理が有効にされています (Workers: {1}、Scope: {2})。
-
-
-
-
-
- 無効な値 '{0}' が 'Scope' に指定されました。サポートされているスコープは {1} です。
- 'Scope' is a setting name that shouldn't be localized.
-
-
-
- 無効な値 '{0}' が 'Workers' に指定されました。値は負ではない整数である必要があります。
- `Workers` is a setting name that shouldn't be localized.
-
-
-
- アセンブリ {0} からテストを検出できませんでした。理由:{1}
-
-
-
-
-
- データ ドリブン テスト メソッドのみがパラメーターを使用できます。[DataRow] または [DynamicData] の使用を意図していましたか?
-
-
-
-
-
- テスト '{0}' の実行が中止されました。
-
-
-
-
-
+
+
+
+
+
+
+ テスト '{0}' は実行タイムアウトを超えました。
+
+
+
+
+ 指定されたソースのいずれかでのテストの実行は、選択されたプラットフォームでサポートされていません
+
+
+
+
+ TestCleanup メソッド {0}.{1} は例外をスローしました。{2}: {3}。
+
+
+
+
+ --- 内部例外スタック トレースの終わり ---
+
+
+
+
+ UTA014: {0}: 1 つのアセンブリ内で、AssemblyCleanup 属性を伴う 2 つ以上のメソッドを定義することはできません。
+
+
+
+
+ UTA013: {0}: 1 つのアセンブリ内で、AssemblyInitialize 属性を伴う 2 つ以上のメソッドを定義することはできません。
+
+
+
+
+ UTA026: {0}: 1 つのクラス内で、ClassCleanup 属性を伴う 2 つ以上のメソッドを定義することはできません。
+
+
+
+
+ UTA025: {0}: 1 つのクラス内で、ClassInitialize 属性を伴う 2 つ以上のメソッドを定義することはできません。
+
+
+
+
+ UTA024: {0}: TestCleanup 属性を伴う 2 つ以上のメソッドを定義することはできません。
+
+
+
+
+ UTA018: {0}: TestInitialize 属性を伴う 2 つ以上のメソッドを定義することはできません。
+
+
+
+
+ 初期化メソッド {0}.{1} は例外をスローしました。{2}。
+
+
+
+
+ クラス {0} のインスタンスを作成できません。エラー: {1}。
+
+
+
+
+ クラス {0} の TestContext プロパティを設定できません。エラー: {1}。
+
+
+
+
+ (例外が発生したため、型 {0} の例外のメッセージを取得できませんでした。)
+
+
+
+
+ UTA031: クラス {0} は有効な TestContext プロパティを含んでいません。TestContext は、型 TestContext でなければなりません。また、non-static および public である必要があり、読み取り専用に指定することはできません。例: public TestContext TestContext。
+
+
+
+
+ UTA001: TestClass 属性がパブリックでないクラス {0} で定義されています
+
+
+
+
+ MSTestAdapter でアセンブリ '{1}' のクラス '{0}' にテストが見つかりませんでした。理由 {2}。
+
+
+
+
+ {0}: {1}
+
+
+
+
+ テスト ソース '{0}' から型を読み込むことができません。このソース内の一部またはすべてのテストが見つからない可能性があります。
+エラー: {1}
+
+
+
+
+ UTA015: ジェネリック メソッドがテスト メソッドになることはできません。{0}.{1} のシグネチャは無効です
+
+
+
+
+ パラメーターを null または空にすることはできません。
+
+
+
+
+ パラメーターはゼロよりも大きい必要があります。
+
+
+
+
+ MSTestAdapter でアセンブリ '{1}' のクラス '{0}' にテストが見つかりませんでした。理由 {2}。
+
+
+
+
+ ファイルが存在しません: {0}
+
+
+
+
+ UTA007: クラス {0} で定義されたメソッド {1} は正しいシグネチャを含んでいません。[TestMethod] 属性を伴って設定されたテスト メソッドは non-static、public にする必要があり、戻り値の型は void でなければなりません。また、パラメーターを受け取ることはできません。例: public void Test.Class1.Test()。また、テスト メソッドで async-await を使用する場合、戻り値の型は Task にする必要があります。例: public async Task Test.Class1.Test2()
+
+
+
+
+ TestContext を Null にすることはできません。
+
+
+
+
+ アセンブリ クリーンアップ メソッド {0}.{1} に失敗しました。エラー メッセージ: {2}。スタック トレース: {3}
+
+
+
+
+ アセンブリ初期化メソッド {0}.{1} は例外をスローしました。{2}: {3}。テストの実行を中止しています。
+
+
+
+
+ クラス クリーンアップ メソッド {0}.{1} に失敗しました。エラー メッセージ: {2}。スタック トレース: {3}
+
+
+
+
+ クラス初期化メソッド {0}.{1} は例外をスローしました。{2}: {3}。
+
+
+
+
+ テストの実行中に例外がスローされました。TestMethodAttribute の拡張クラスを使用している場合は、ベンダーに連絡してください。エラー メッセージ: {0}
+
+
+
+
+ テストの実行中にエラーが発生しました。拡張から結果が返されませんでした。TestMethodAttribute の拡張クラスを使用している場合は、ベンダーに連絡してください。
+
+
+
+
+ メソッド {0}.{1} は不適切なシグネチャを含んでいます。メソッドは static および public である必要があり、値を返しません。また、パラメーターを受け取ることはできません。さらに、メソッドで async-await を使用している場合、戻り値の型は Task である必要があります。
+
+
+
+
+ メソッド {0}.{1} は不適切なシグネチャを含んでいます。メソッドは static および public である必要があり、値を返しません。また、TestContext 型の 1 つのパラメーターを受け取る必要があります。さらに、メソッドで async-await を使用している場合、戻り値の型は Task である必要があります。
+
+
+
+
+ UTA054: {0}.{1} は無効な Timeout 属性を含んでいます。タイムアウトは有効な整数値でなければなりません。0 よりも小さい値にすることはできません。
+
+
+
+
+ UTA023: {0}: メソッド {1} 上の以前に定義されたプロパティ {2} を定義することはできません。
+
+
+
+
+ UTA022: {0}.{1}: カスタム プロパティ "{2}" は既に定義されています。"{3}" を値として使用しています。
+
+
+
+
+ UTA021: {0}: Null または空のカスタム プロパティが、メソッド {1} で定義されています。カスタム プロパティには有効な名前を指定しなければなりません。
+
+
+
+
+ メソッド {0}.{1} は存在しません。
+
+
+
+
+ クラス {0} の既定コンストラクターを取得できません。
+
+
+
+
+ プロパティ {0}.TestContext が見つかりません。エラー: {1}。
+
+
+
+
+ {0}.TestContext は不適切な型を含んでいます。
+
+
+
+
+ メソッド {0}.{1} は不適切なシグネチャを含んでいます。メソッドは non-static および public である必要があり、値を返しません。また、パラメーターを受け取ることはできません。さらに、メソッドで async-await を使用している場合、戻り値の型は Task である必要があります。
+
+
+
+
+ 型 {0} を取得できません。エラー: {1}。
+
+
+
+
+ テスト メソッド {0} が見つかりませんでした。
+
+
+
+
+ デバッグ トレース:
+
+
+
+
+ テスト メソッド {0}.{1} によってスローされた例外を取得できませんでした。
+
+
+
+
+ テスト メソッド {0}.{1} が例外をスローしました:
+{2}
+
+
+
+
+ {0} UWP プロジェクトについて、テスト内で UI オブジェクトを使用している場合は、[TestMethod] の代わりに [UITestMethod] 属性を使用して UI スレッド内でテストを実行することを検討してください。
+
+
+
+
+ MSTestAdapterV2
+
+
+
+
+ 設定 '{0}' は無効です。予期しない XmlAttribute: '{1}'。
+
+
+
+
+ 設定 '{0}' は無効です。予期しない XmlElement: '{1}'。
+
+
+
+
+ {0} (データ行 {1})
+
+
+
+
+ テスト メソッド {0}.{1} に定義されている ExpectedException 属性が、作成中に例外をスローしました。
+{2}
+
+
+
+
+ テスト メソッド {0}.{1} には、ExpectedExceptionBaseAttribute から派生した属性が複数定義されています。このような属性は 1 つしか許可されません。
+
+
+
+
+ 警告: testsettings ファイル、vsmdi ファイルは MSTest V2 アダプターではサポートされていません。
+
+
+
+
+ TestContext メッセージ:
+
+
+
+
+ テスト クラス {0} のテスト クリーンアップ メソッドの呼び出しでエラーが発生しました: {1}
+
+
+
+
+ TestCleanup スタック トレース
+
+
+
+
+ [MSTest][Discovery][{0}] {1}
+
+
+
+
+ MSTest 実行プログラム: {0} でテスト並列処理が有効にされています (Workers: {1}、Scope: {2})。
+
+
+
+
+ 無効な値 '{0}' が 'Scope' に指定されました。サポートされているスコープは {1} です。
+ 'Scope' is a setting name that shouldn't be localized.
+
+
+
+ 無効な値 '{0}' が 'Workers' に指定されました。値は負ではない整数である必要があります。
+ `Workers` is a setting name that shouldn't be localized.
+
+
+
+ アセンブリ {0} からテストを検出できませんでした。理由:{1}
+
+
+
+
+ データ ドリブン テスト メソッドのみがパラメーターを使用できます。[DataRow] または [DynamicData] の使用を意図していましたか?
+
+
+
+
+ テスト '{0}' の実行が中止されました。
+
+
+
+
\ No newline at end of file
diff --git a/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.ko.xlf b/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.ko.xlf
index 376a6c5bc..c25951285 100644
--- a/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.ko.xlf
+++ b/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.ko.xlf
@@ -1,407 +1,343 @@
-
-
-
-
-
-
- '{0}' 테스트가 실행 시간 제한을 초과했습니다.
-
-
-
-
-
- 선택된 플랫폼의 경우 제공된 소스에서 테스트를 실행할 수 없습니다.
-
-
-
-
-
- TestCleanup 메서드 {0}.{1}에서 예외를 throw했습니다. {2}: {3}.
-
-
-
-
-
- --- 내부 예외 스택 추적의 끝 ---
-
-
-
-
-
- UTA014: {0}: 어셈블리 내부에서 AssemblyCleanup 특성을 사용하는 메서드를 여러 개 정의할 수 없습니다.
-
-
-
-
-
- UTA013: {0}: 어셈블리 내부에서 AssemblyInitialize 특성을 사용하는 메서드를 여러 개 정의할 수 없습니다.
-
-
-
-
-
- UTA026: {0}: 클래스 내부에서 ClassCleanup 특성을 사용하는 메서드를 여러 개 정의할 수 없습니다.
-
-
-
-
-
- UTA025: {0}: 클래스 내부에서 ClassInitialize 특성을 사용하는 메서드를 여러 개 정의할 수 없습니다.
-
-
-
-
-
- UTA024: {0}: TestCleanup 특성을 사용하는 메서드를 여러 개 정의할 수 없습니다.
-
-
-
-
-
- UTA018: {0}: TestInitialize 특성을 사용하는 메서드를 여러 개 정의할 수 없습니다.
-
-
-
-
-
- 초기화 메서드 {0}.{1}에서 예외를 throw했습니다. {2}.
-
-
-
-
-
- {0} 클래스의 인스턴스를 만들 수 없습니다. 오류: {1}
-
-
-
-
-
- {0} 클래스에 대해 TestContext 속성을 설정할 수 없습니다. 오류: {1}
-
-
-
-
-
- (예외로 인해 {0} 형식의 예외에 대한 메시지를 가져오지 못했습니다.)
-
-
-
-
-
- UTA031: {0} 클래스에 올바른 TestContext 속성이 없습니다. TestContext는 TestContext 형식이어야 하고 읽기 전용이 아니어야 하며, static이 아니고 public이어야 합니다. 예: public TestContext TestContext.
-
-
-
-
-
- UTA001: public이 아닌 클래스 {0}에서 TestClass 특성을 정의했습니다.
-
-
-
-
-
- MSTestAdapter가 {2} 때문에 어셈블리 '{1}'의 클래스 '{0}'에서 테스트를 검색하지 못했습니다.
-
-
-
-
-
- {0}: {1}
-
-
-
-
-
- 테스트 소스 '{0}'에서 형식을 로드할 수 없습니다. 이 소스의 일부 또는 모든 테스트를 검색할 수 없습니다.
-오류: {1}
-
-
-
-
-
- UTA015: 제네릭 메서드는 테스트 메서드일 수 없습니다. {0}.{1}에 잘못된 서명이 있습니다.
-
-
-
-
-
- 매개 변수는 null이거나 비워 둘 수 없습니다.
-
-
-
-
-
- 매개 변수는 0보다 커야 합니다.
-
-
-
-
-
- MSTestAdapter가 어셈블리 '{1}'의 클래스 '{0}'에서 테스트를 검색하지 못했습니다. 이유는 {2}입니다.
-
-
-
-
-
- 파일이 없습니다. {0}
-
-
-
-
-
- UTA007: {0} 클래스에 정의된 {1} 메서드의 서명이 잘못되었습니다. [TestMethod] 특성으로 표시된 테스트 메서드는 static이 아니고 public이어야 하며, 반환 형식이 void여야 하고 매개 변수를 사용할 수 없습니다. 예: public void Test.Class1.Test(). 또한 테스트 메서드에서 비동기 대기를 사용하는 경우 반환 형식은 Task여야 합니다. 예: public async Task Test.Class1.Test2()
-
-
-
-
-
- TestContext는 null일 수 없습니다.
-
-
-
-
-
- 어셈블리 정리 메서드 {0}.{1}이(가) 실패했습니다. 오류 메시지: {2}. StackTrace: {3}
-
-
-
-
-
- 어셈블리 초기화 메서드 {0}.{1}에서 예외를 throw했습니다. {2}: {3}. 테스트 실행을 중단합니다.
-
-
-
-
-
- 클래스 정리 메서드 {0}.{1}이(가) 실패했습니다. 오류 메시지: {2}. 스택 추적: {3}
-
-
-
-
-
- 클래스 초기화 메서드 {0}.{1}에서 예외를 throw했습니다. {2}: {3}
-
-
-
-
-
- 테스트를 실행하는 동안 예외가 발생했습니다. TestMethodAttribute 확장을 사용하는 경우 공급업체에 문의하세요. 오류 메시지: {0}
-
-
-
-
-
- 테스트를 실행하는 중에 오류가 발생했습니다. 확장에서 결과가 반환되지 않았습니다. TestMethodAttribute 확장을 사용하는 경우 공급업체에 문의하세요.
-
-
-
-
-
- {0}.{1} 메서드의 서명이 잘못되었습니다. 메서드는 정적이고 공용이어야 하며, 값을 반환하거나 매개 변수를 취하지 않습니다. 또한 메서드에서 비동기 대기를 사용하는 경우 반환 형식은 Task여야 합니다.
-
-
-
-
-
- {0}.{1} 메서드의 서명이 잘못되었습니다. 메서드는 정적이고 공용이어야 하며, 값을 반환하지 않고 TestContext 형식의 매개 변수 한 개를 사용해야 합니다. 또한 메서드에서 비동기 대기를 사용하는 경우 반환 형식은 Task여야 합니다.
-
-
-
-
-
- UTA054: {0}.{1}에 잘못된 Timeout 특성이 있습니다. Timeout은 유효한 정수 값이어야 하며 0보다 작을 수 없습니다.
-
-
-
-
-
- UTA023: {0}: {1} 메서드에서 미리 정의된 속성 {2}을(를) 정의할 수 없습니다.
-
-
-
-
-
- UTA022: {0}.{1}: 사용자 지정 속성 "{2}"은(는) 이미 정의되어 있습니다. 값으로 "{3}"을(를) 사용합니다.
-
-
-
-
-
- UTA021: {0}: {1} 메서드에서 Null 또는 빈 사용자 지정 속성을 정의했습니다. 사용자 지정 속성에는 올바른 이름이 지정되어 있어야 합니다.
-
-
-
-
-
- {0}.{1} 메서드가 없습니다.
-
-
-
-
-
- {0} 클래스의 기본 생성자를 가져올 수 없습니다.
-
-
-
-
-
- {0}.TestContext 속성을 찾을 수 없습니다. 오류: {1}
-
-
-
-
-
- {0}.TestContext의 형식이 잘못되었습니다.
-
-
-
-
-
- {0}.{1} 메서드의 서명이 잘못되었습니다. 메서드는 정적이 아니고 공용이어야 하며, 값을 반환하거나 매개 변수를 사용할 수 없습니다. 또한 메서드에서 비동기 대기를 사용하는 경우 반환 형식은 Task여야 합니다.
-
-
-
-
-
- {0} 형식을 가져올 수 없습니다. 오류: {1}
-
-
-
-
-
- {0} 테스트 메서드를 찾을 수 없습니다.
-
-
-
-
-
- 디버그 추적:
-
-
-
-
-
- 테스트 메서드 {0}.{1}에서 throw한 예외를 가져오지 못했습니다.
-
-
-
-
-
- 테스트 메서드 {0}.{1}에서 예외를 throw했습니다.
-{2}
-
-
-
-
-
- {0} UWP 프로젝트의 경우 테스트에서 UI 개체를 사용 중이면 [TestMethod] 대신 [UITestMethod] 특성을 사용하여 UI 스레드에서 테스트를 실행하세요.
-
-
-
-
-
- MSTestAdapterV2
-
-
-
-
-
- '{0}' 설정이 잘못되었습니다. 예기치 않은 XmlAttribute '{1}'이(가) 있습니다.
-
-
-
-
-
- '{0}' 설정이 잘못되었습니다. 예기치 않은 XmlElement '{1}'이(가) 있습니다.
-
-
-
-
-
- {0}(데이터 행 {1})
-
-
-
-
-
- 테스트 메서드 {0}.{1}에 정의된 ExpectedException 특성이 생성하는 동안 예외를 throw했습니다.
-{2}
-
-
-
-
-
- 테스트 메서드 {0}.{1}에는 정의되어 있는 ExpectedExceptionBaseAttribute에서 파생된 특성이 여러 개 있습니다. 이러한 특성은 하나만 허용됩니다.
-
-
-
-
-
- 경고: MSTest V2 어댑터에서는 testsettings 파일 또는 vsmdi 파일이 지원되지 않습니다.
-
-
-
-
-
- TestContext 메시지:
-
-
-
-
-
- 테스트 클래스 {0}에 대한 테스트 정리 메서드를 호출하는 오류: {1}
-
-
-
-
-
- TestCleanup 스택 추적
-
-
-
-
-
- [MSTest][검색][{0}] {1}
-
-
-
-
-
- MSTest 실행기: {0}에 대해 테스트 병렬 처리를 사용합니다(Workers: {1}, Scope: {2}).
-
-
-
-
-
- 'Scope'에 대해 잘못된 값 '{0}'이(가) 지정되었습니다. 지원되는 범위는 {1}입니다.
- 'Scope' is a setting name that shouldn't be localized.
-
-
-
- 'Workers'에 대해 잘못된 값 '{0}'이(가) 지정되었습니다. 이 값은 음수가 아닌 정수여야 합니다.
- `Workers` is a setting name that shouldn't be localized.
-
-
-
- 어셈블리 {0}에서 테스트를 검색하지 못했습니다. 이유:{1}
-
-
-
-
-
- 데이터 기반 테스트 메서드에만 매개 변수를 포함할 수 있습니다. [DataRow] 또는 [DynamicData]를 사용하려고 하셨습니까?
-
-
-
-
-
- 테스트 '{0}' 실행이 중단되었습니다.
-
-
-
-
-
+
+
+
+
+
+
+ '{0}' 테스트가 실행 시간 제한을 초과했습니다.
+
+
+
+
+ 선택된 플랫폼의 경우 제공된 소스에서 테스트를 실행할 수 없습니다.
+
+
+
+
+ TestCleanup 메서드 {0}.{1}에서 예외를 throw했습니다. {2}: {3}.
+
+
+
+
+ --- 내부 예외 스택 추적의 끝 ---
+
+
+
+
+ UTA014: {0}: 어셈블리 내부에서 AssemblyCleanup 특성을 사용하는 메서드를 여러 개 정의할 수 없습니다.
+
+
+
+
+ UTA013: {0}: 어셈블리 내부에서 AssemblyInitialize 특성을 사용하는 메서드를 여러 개 정의할 수 없습니다.
+
+
+
+
+ UTA026: {0}: 클래스 내부에서 ClassCleanup 특성을 사용하는 메서드를 여러 개 정의할 수 없습니다.
+
+
+
+
+ UTA025: {0}: 클래스 내부에서 ClassInitialize 특성을 사용하는 메서드를 여러 개 정의할 수 없습니다.
+
+
+
+
+ UTA024: {0}: TestCleanup 특성을 사용하는 메서드를 여러 개 정의할 수 없습니다.
+
+
+
+
+ UTA018: {0}: TestInitialize 특성을 사용하는 메서드를 여러 개 정의할 수 없습니다.
+
+
+
+
+ 초기화 메서드 {0}.{1}에서 예외를 throw했습니다. {2}.
+
+
+
+
+ {0} 클래스의 인스턴스를 만들 수 없습니다. 오류: {1}
+
+
+
+
+ {0} 클래스에 대해 TestContext 속성을 설정할 수 없습니다. 오류: {1}
+
+
+
+
+ (예외로 인해 {0} 형식의 예외에 대한 메시지를 가져오지 못했습니다.)
+
+
+
+
+ UTA031: {0} 클래스에 올바른 TestContext 속성이 없습니다. TestContext는 TestContext 형식이어야 하고 읽기 전용이 아니어야 하며, static이 아니고 public이어야 합니다. 예: public TestContext TestContext.
+
+
+
+
+ UTA001: public이 아닌 클래스 {0}에서 TestClass 특성을 정의했습니다.
+
+
+
+
+ MSTestAdapter가 {2} 때문에 어셈블리 '{1}'의 클래스 '{0}'에서 테스트를 검색하지 못했습니다.
+
+
+
+
+ {0}: {1}
+
+
+
+
+ 테스트 소스 '{0}'에서 형식을 로드할 수 없습니다. 이 소스의 일부 또는 모든 테스트를 검색할 수 없습니다.
+오류: {1}
+
+
+
+
+ UTA015: 제네릭 메서드는 테스트 메서드일 수 없습니다. {0}.{1}에 잘못된 서명이 있습니다.
+
+
+
+
+ 매개 변수는 null이거나 비워 둘 수 없습니다.
+
+
+
+
+ 매개 변수는 0보다 커야 합니다.
+
+
+
+
+ MSTestAdapter가 어셈블리 '{1}'의 클래스 '{0}'에서 테스트를 검색하지 못했습니다. 이유는 {2}입니다.
+
+
+
+
+ 파일이 없습니다. {0}
+
+
+
+
+ UTA007: {0} 클래스에 정의된 {1} 메서드의 서명이 잘못되었습니다. [TestMethod] 특성으로 표시된 테스트 메서드는 static이 아니고 public이어야 하며, 반환 형식이 void여야 하고 매개 변수를 사용할 수 없습니다. 예: public void Test.Class1.Test(). 또한 테스트 메서드에서 비동기 대기를 사용하는 경우 반환 형식은 Task여야 합니다. 예: public async Task Test.Class1.Test2()
+
+
+
+
+ TestContext는 null일 수 없습니다.
+
+
+
+
+ 어셈블리 정리 메서드 {0}.{1}이(가) 실패했습니다. 오류 메시지: {2}. StackTrace: {3}
+
+
+
+
+ 어셈블리 초기화 메서드 {0}.{1}에서 예외를 throw했습니다. {2}: {3}. 테스트 실행을 중단합니다.
+
+
+
+
+ 클래스 정리 메서드 {0}.{1}이(가) 실패했습니다. 오류 메시지: {2}. 스택 추적: {3}
+
+
+
+
+ 클래스 초기화 메서드 {0}.{1}에서 예외를 throw했습니다. {2}: {3}
+
+
+
+
+ 테스트를 실행하는 동안 예외가 발생했습니다. TestMethodAttribute 확장을 사용하는 경우 공급업체에 문의하세요. 오류 메시지: {0}
+
+
+
+
+ 테스트를 실행하는 중에 오류가 발생했습니다. 확장에서 결과가 반환되지 않았습니다. TestMethodAttribute 확장을 사용하는 경우 공급업체에 문의하세요.
+
+
+
+
+ {0}.{1} 메서드의 서명이 잘못되었습니다. 메서드는 정적이고 공용이어야 하며, 값을 반환하거나 매개 변수를 취하지 않습니다. 또한 메서드에서 비동기 대기를 사용하는 경우 반환 형식은 Task여야 합니다.
+
+
+
+
+ {0}.{1} 메서드의 서명이 잘못되었습니다. 메서드는 정적이고 공용이어야 하며, 값을 반환하지 않고 TestContext 형식의 매개 변수 한 개를 사용해야 합니다. 또한 메서드에서 비동기 대기를 사용하는 경우 반환 형식은 Task여야 합니다.
+
+
+
+
+ UTA054: {0}.{1}에 잘못된 Timeout 특성이 있습니다. Timeout은 유효한 정수 값이어야 하며 0보다 작을 수 없습니다.
+
+
+
+
+ UTA023: {0}: {1} 메서드에서 미리 정의된 속성 {2}을(를) 정의할 수 없습니다.
+
+
+
+
+ UTA022: {0}.{1}: 사용자 지정 속성 "{2}"은(는) 이미 정의되어 있습니다. 값으로 "{3}"을(를) 사용합니다.
+
+
+
+
+ UTA021: {0}: {1} 메서드에서 Null 또는 빈 사용자 지정 속성을 정의했습니다. 사용자 지정 속성에는 올바른 이름이 지정되어 있어야 합니다.
+
+
+
+
+ {0}.{1} 메서드가 없습니다.
+
+
+
+
+ {0} 클래스의 기본 생성자를 가져올 수 없습니다.
+
+
+
+
+ {0}.TestContext 속성을 찾을 수 없습니다. 오류: {1}
+
+
+
+
+ {0}.TestContext의 형식이 잘못되었습니다.
+
+
+
+
+ {0}.{1} 메서드의 서명이 잘못되었습니다. 메서드는 정적이 아니고 공용이어야 하며, 값을 반환하거나 매개 변수를 사용할 수 없습니다. 또한 메서드에서 비동기 대기를 사용하는 경우 반환 형식은 Task여야 합니다.
+
+
+
+
+ {0} 형식을 가져올 수 없습니다. 오류: {1}
+
+
+
+
+ {0} 테스트 메서드를 찾을 수 없습니다.
+
+
+
+
+ 디버그 추적:
+
+
+
+
+ 테스트 메서드 {0}.{1}에서 throw한 예외를 가져오지 못했습니다.
+
+
+
+
+ 테스트 메서드 {0}.{1}에서 예외를 throw했습니다.
+{2}
+
+
+
+
+ {0} UWP 프로젝트의 경우 테스트에서 UI 개체를 사용 중이면 [TestMethod] 대신 [UITestMethod] 특성을 사용하여 UI 스레드에서 테스트를 실행하세요.
+
+
+
+
+ MSTestAdapterV2
+
+
+
+
+ '{0}' 설정이 잘못되었습니다. 예기치 않은 XmlAttribute '{1}'이(가) 있습니다.
+
+
+
+
+ '{0}' 설정이 잘못되었습니다. 예기치 않은 XmlElement '{1}'이(가) 있습니다.
+
+
+
+
+ {0}(데이터 행 {1})
+
+
+
+
+ 테스트 메서드 {0}.{1}에 정의된 ExpectedException 특성이 생성하는 동안 예외를 throw했습니다.
+{2}
+
+
+
+
+ 테스트 메서드 {0}.{1}에는 정의되어 있는 ExpectedExceptionBaseAttribute에서 파생된 특성이 여러 개 있습니다. 이러한 특성은 하나만 허용됩니다.
+
+
+
+
+ 경고: MSTest V2 어댑터에서는 testsettings 파일 또는 vsmdi 파일이 지원되지 않습니다.
+
+
+
+
+ TestContext 메시지:
+
+
+
+
+ 테스트 클래스 {0}에 대한 테스트 정리 메서드를 호출하는 오류: {1}
+
+
+
+
+ TestCleanup 스택 추적
+
+
+
+
+ [MSTest][검색][{0}] {1}
+
+
+
+
+ MSTest 실행기: {0}에 대해 테스트 병렬 처리를 사용합니다(Workers: {1}, Scope: {2}).
+
+
+
+
+ 'Scope'에 대해 잘못된 값 '{0}'이(가) 지정되었습니다. 지원되는 범위는 {1}입니다.
+ 'Scope' is a setting name that shouldn't be localized.
+
+
+
+ 'Workers'에 대해 잘못된 값 '{0}'이(가) 지정되었습니다. 이 값은 음수가 아닌 정수여야 합니다.
+ `Workers` is a setting name that shouldn't be localized.
+
+
+
+ 어셈블리 {0}에서 테스트를 검색하지 못했습니다. 이유:{1}
+
+
+
+
+ 데이터 기반 테스트 메서드에만 매개 변수를 포함할 수 있습니다. [DataRow] 또는 [DynamicData]를 사용하려고 하셨습니까?
+
+
+
+
+ 테스트 '{0}' 실행이 중단되었습니다.
+
+
+
+
\ No newline at end of file
diff --git a/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.pl.xlf b/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.pl.xlf
index f4b2557f6..b1a88cac4 100644
--- a/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.pl.xlf
+++ b/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.pl.xlf
@@ -1,407 +1,343 @@
-
-
-
-
-
-
- Test „{0}” przekroczył okres limitu czasu na wykonanie.
-
-
-
-
-
- Uruchamianie testów w żadnym z podanych źródeł nie jest obsługiwane dla wybranej platformy
-
-
-
-
-
- Metoda TestCleanup {0}.{1} zgłosiła wyjątek. {2}: {3}.
-
-
-
-
-
- --- Koniec śledzenia stosu wyjątku wewnętrznego ---
-
-
-
-
-
- UTA014: {0}: W zestawie nie można zdefiniować więcej niż jednej metody z atrybutem AssemblyCleanup.
-
-
-
-
-
- UTA013: {0}: W zestawie nie można zdefiniować więcej niż jednej metody z atrybutem AssemblyInitialize.
-
-
-
-
-
- UTA026: {0}: W klasie nie można zdefiniować więcej niż jednej metody z atrybutem ClassCleanup.
-
-
-
-
-
- UTA025: {0}: W klasie nie można zdefiniować więcej niż jednej metody z atrybutem ClassInitialize.
-
-
-
-
-
- UTA024: {0}: Nie można zdefiniować więcej niż jednej metody z atrybutem TestCleanup.
-
-
-
-
-
- UTA018: {0}: Nie można zdefiniować więcej niż jednej metody z atrybutem TestInitialize.
-
-
-
-
-
- Metoda inicjowania {0}.{1} zgłosiła wyjątek. {2}.
-
-
-
-
-
- Nie można utworzyć wystąpienia klasy {0}. Błąd: {1}.
-
-
-
-
-
- Nie można ustawić właściwości TestContext w klasie {0}. Błąd: {1}.
-
-
-
-
-
- (Nie można pobrać komunikatu dotyczącego wyjątku typu {0} z powodu wyjątku).
-
-
-
-
-
- UTA031: Klasa {0} nie ma prawidłowej właściwości TestContext. Właściwość TestContext musi być typu TestContext, niestatyczna, publiczna i nie może być tylko do odczytu. Na przykład : public TestContext TestContext.
-
-
-
-
-
- UTA001: Atrybut TestClass zdefiniowany dla niepublicznej klasy {0}
-
-
-
-
-
- Adapter MSTestAdapter nie mógł odnaleźć testów w klasie „{0}” zestawu „{1}”, przyczyna: {2}.
-
-
-
-
-
- {0}: {1}
-
-
-
-
-
- Nie można załadować typów ze źródła testów „{0}”. Niektóre lub wszystkie testy w tym źródle mogły nie zostać odnalezione.
-Błąd: {1}
-
-
-
-
-
- UTA015: Metoda ogólna nie może być metodą testową. {0}{1} ma nieprawidłową sygnaturę
-
-
-
-
-
- Parametr nie może mieć wartości null ani być pusty.
-
-
-
-
-
- Parametr musi być większy od zera.
-
-
-
-
-
- Adapter MSTestAdapter nie mógł odnaleźć testów w klasie „{0}” zestawu „{1}”. Przyczyna: {2}.
-
-
-
-
-
- Plik nie istnieje: {0}
-
-
-
-
-
- UTA007: Metoda {1} zdefiniowana w klasie {0} nie ma poprawnej sygnatury. Metoda testowa oznaczona przez atrybut [TestMethod] musi być niestatyczna, publiczna, zwracać wartość typu void i nie powinna przyjmować żadnego parametru. Przykład: public void Test.Class1.Test(). Ponadto zwracana wartość musi być typu Task, gdy w metodzie testowej jest używane oczekiwanie asynchroniczne. Przykład: public async Task Test.Class1.Test2()
-
-
-
-
-
- Wartość TestContext nie może być równa null.
-
-
-
-
-
- Metoda czyszczenia zestawu {0}.{1} nie powiodła się. Komunikat o błędzie: {2}. Ślad stosu: {3}
-
-
-
-
-
- Metoda inicjująca zestaw {0}.{1} nie powiodła się. {2}: {3}. Przerywanie wykonywania testu.
-
-
-
-
-
- Metoda czyszczenia klasy {0}.{1} nie powiodła się. Komunikat o błędzie: {2}. Ślad stosu: {3}
-
-
-
-
-
- Metoda inicjowania klasy {0}.{1} zgłosiła wyjątek. {2}: {3}.
-
-
-
-
-
- Zgłoszono wyjątek podczas wykonywania testu. W przypadku korzystania z rozszerzenia atrybutu TestMethodAttribute należy skontaktować się z dostawcą. Komunikat o błędzie: {0}
-
-
-
-
-
- Błąd podczas wykonywania testu. Rozszerzenie nie zwróciło żadnego wyniku. W przypadku korzystania z rozszerzenia atrybutu TestMethodAttribute należy skontaktować się z dostawcą.
-
-
-
-
-
- Metoda {0}.{1} ma nieprawidłową sygnaturę. Metoda musi być statyczna i publiczna, nie może zwracać wartości i nie powinna przyjmować żadnego parametru. Ponadto jeśli w metodzie jest używane oczekiwanie asynchroniczne, zwracanym typem musi być typ Task.
-
-
-
-
-
- Metoda {0}.{1} ma nieprawidłową sygnaturę. Metoda musi być statyczna i publiczna, nie może zwracać wartości i nie powinna przyjmować pojedynczego parametru typu TestContext. Ponadto jeśli w metodzie jest używane oczekiwanie asynchroniczne, zwracanym typem musi być typ Task.
-
-
-
-
-
- UTA054: {0}.{1} ma nieprawidłowy atrybut Timeout. Limit czasu musi być prawidłową liczbą całkowitą i nie może być mniejszy niż 0.
-
-
-
-
-
- UTA023: {0}: Nie można zdefiniować wstępnie zdefiniowanej właściwości {2} dla metody {1}.
-
-
-
-
-
- UTA022: {0}.{1}: Właściwość niestandardowa „{2}” jest już zdefiniowana. Jako wartość jest używane „{3}”.
-
-
-
-
-
- UTA021: {0}: Zerowa lub pusta niestandardowa właściwość została zdefiniowana dla metody {1}. Niestandardowa właściwość musi mieć prawidłową nazwę.
-
-
-
-
-
- Metoda {0}.{1} nie istnieje.
-
-
-
-
-
- Nie można pobrać domyślnego konstruktora dla klasy {0}.
-
-
-
-
-
- Nie można znaleźć właściwości {0}.TestContext. Błąd:{1}.
-
-
-
-
-
- Element {0}.TestContext ma niepoprawny typ.
-
-
-
-
-
- Metoda {0}.{1} ma nieprawidłową sygnaturę. Metoda musi być niestatyczna i publiczna, nie może zwracać wartości i nie powinna przyjmować żadnego parametru. Ponadto jeśli w metodzie jest używane oczekiwanie asynchroniczne, zwracanym typem musi być typ Task.
-
-
-
-
-
- Nie można uzyskać typu {0}. Błąd: {1}.
-
-
-
-
-
- Nie znaleziono metody testowej {0}.
-
-
-
-
-
- Ślad debugowania:
-
-
-
-
-
- Nie powiodło się uzyskanie wyjątku zgłoszonego przez metodę testową {0}.{1}.
-
-
-
-
-
- Metoda testowa {0}.{1} zgłosiła wyjątek:
-{2}
-
-
-
-
-
- {0} Jeśli w projektach UWP korzystasz z obiektów interfejsu użytkownika podczas testowania, rozważ użycie atrybutu [UITestMethod] zamiast atrybutu [TestMethod], aby wykonywać test w wątku interfejsu użytkownika.
-
-
-
-
-
- MSTestAdapterV2
-
-
-
-
-
- Nieprawidłowe ustawienia „{0}”. Nieoczekiwany atrybut XmlAttribute: „{1}”.
-
-
-
-
-
- Nieprawidłowe ustawienia „{0}”. Nieoczekiwany atrybut XmlElement: „{1}”.
-
-
-
-
-
- {0} (wiersz danych {1})
-
-
-
-
-
- Atrybut ExpectedException zdefiniowany dla metody testowej {0}.{1} zgłosił wyjątek w trakcie konstruowania.
-{2}
-
-
-
-
-
- Metoda testowa {0}.{1} ma wiele zdefiniowanych dla niej atrybutów pochodzących od atrybutu ExpectedExceptionBaseAttribute. Dozwolony jest tylko jeden taki atrybut.
-
-
-
-
-
- Ostrzeżenie: Plik testsettings lub plik vsmdi nie jest obsługiwany przez adapter MSTest w wersji 2.
-
-
-
-
-
- Komunikaty TestContext:
-
-
-
-
-
- Błąd podczas wywoływania metody czyszczącej testu dla klasy testowej {0}: {1}
-
-
-
-
-
- Ślad stosu dla TestCleanup
-
-
-
-
-
- [MSTest][Discovery][{0}] {1}
-
-
-
-
-
- Moduł wykonywania MSTest: włączono obsługę równoległego wykonywania testów dla elementu {0} (procesy robocze: {1}, zakres: {2}).
-
-
-
-
-
- Określono nieprawidłową wartość „{0}” dla właściwości „Scope”. Obsługiwane zakresy to {1}.
- 'Scope' is a setting name that shouldn't be localized.
-
-
-
- Określono nieprawidłową wartość „{0}” dla właściwości „Workers”. Wartość musi być nieujemną liczbą całkowitą.
- `Workers` is a setting name that shouldn't be localized.
-
-
-
- Nie można odnaleźć testów z zestawu {0}. Przyczyna:{1}
-
-
-
-
-
- Tylko metody testowe bazujące na danych mogą mieć parametry. Czy chodziło Ci o użycie elementu [DataRow] lub [DynamicData]?
-
-
-
-
-
- Wykonanie testu „{0}” zostało przerwane.
-
-
-
-
-
+
+
+
+
+
+
+ Test „{0}” przekroczył okres limitu czasu na wykonanie.
+
+
+
+
+ Uruchamianie testów w żadnym z podanych źródeł nie jest obsługiwane dla wybranej platformy
+
+
+
+
+ Metoda TestCleanup {0}.{1} zgłosiła wyjątek. {2}: {3}.
+
+
+
+
+ --- Koniec śledzenia stosu wyjątku wewnętrznego ---
+
+
+
+
+ UTA014: {0}: W zestawie nie można zdefiniować więcej niż jednej metody z atrybutem AssemblyCleanup.
+
+
+
+
+ UTA013: {0}: W zestawie nie można zdefiniować więcej niż jednej metody z atrybutem AssemblyInitialize.
+
+
+
+
+ UTA026: {0}: W klasie nie można zdefiniować więcej niż jednej metody z atrybutem ClassCleanup.
+
+
+
+
+ UTA025: {0}: W klasie nie można zdefiniować więcej niż jednej metody z atrybutem ClassInitialize.
+
+
+
+
+ UTA024: {0}: Nie można zdefiniować więcej niż jednej metody z atrybutem TestCleanup.
+
+
+
+
+ UTA018: {0}: Nie można zdefiniować więcej niż jednej metody z atrybutem TestInitialize.
+
+
+
+
+ Metoda inicjowania {0}.{1} zgłosiła wyjątek. {2}.
+
+
+
+
+ Nie można utworzyć wystąpienia klasy {0}. Błąd: {1}.
+
+
+
+
+ Nie można ustawić właściwości TestContext w klasie {0}. Błąd: {1}.
+
+
+
+
+ (Nie można pobrać komunikatu dotyczącego wyjątku typu {0} z powodu wyjątku).
+
+
+
+
+ UTA031: Klasa {0} nie ma prawidłowej właściwości TestContext. Właściwość TestContext musi być typu TestContext, niestatyczna, publiczna i nie może być tylko do odczytu. Na przykład : public TestContext TestContext.
+
+
+
+
+ UTA001: Atrybut TestClass zdefiniowany dla niepublicznej klasy {0}
+
+
+
+
+ Adapter MSTestAdapter nie mógł odnaleźć testów w klasie „{0}” zestawu „{1}”, przyczyna: {2}.
+
+
+
+
+ {0}: {1}
+
+
+
+
+ Nie można załadować typów ze źródła testów „{0}”. Niektóre lub wszystkie testy w tym źródle mogły nie zostać odnalezione.
+Błąd: {1}
+
+
+
+
+ UTA015: Metoda ogólna nie może być metodą testową. {0}{1} ma nieprawidłową sygnaturę
+
+
+
+
+ Parametr nie może mieć wartości null ani być pusty.
+
+
+
+
+ Parametr musi być większy od zera.
+
+
+
+
+ Adapter MSTestAdapter nie mógł odnaleźć testów w klasie „{0}” zestawu „{1}”. Przyczyna: {2}.
+
+
+
+
+ Plik nie istnieje: {0}
+
+
+
+
+ UTA007: Metoda {1} zdefiniowana w klasie {0} nie ma poprawnej sygnatury. Metoda testowa oznaczona przez atrybut [TestMethod] musi być niestatyczna, publiczna, zwracać wartość typu void i nie powinna przyjmować żadnego parametru. Przykład: public void Test.Class1.Test(). Ponadto zwracana wartość musi być typu Task, gdy w metodzie testowej jest używane oczekiwanie asynchroniczne. Przykład: public async Task Test.Class1.Test2()
+
+
+
+
+ Wartość TestContext nie może być równa null.
+
+
+
+
+ Metoda czyszczenia zestawu {0}.{1} nie powiodła się. Komunikat o błędzie: {2}. Ślad stosu: {3}
+
+
+
+
+ Metoda inicjująca zestaw {0}.{1} nie powiodła się. {2}: {3}. Przerywanie wykonywania testu.
+
+
+
+
+ Metoda czyszczenia klasy {0}.{1} nie powiodła się. Komunikat o błędzie: {2}. Ślad stosu: {3}
+
+
+
+
+ Metoda inicjowania klasy {0}.{1} zgłosiła wyjątek. {2}: {3}.
+
+
+
+
+ Zgłoszono wyjątek podczas wykonywania testu. W przypadku korzystania z rozszerzenia atrybutu TestMethodAttribute należy skontaktować się z dostawcą. Komunikat o błędzie: {0}
+
+
+
+
+ Błąd podczas wykonywania testu. Rozszerzenie nie zwróciło żadnego wyniku. W przypadku korzystania z rozszerzenia atrybutu TestMethodAttribute należy skontaktować się z dostawcą.
+
+
+
+
+ Metoda {0}.{1} ma nieprawidłową sygnaturę. Metoda musi być statyczna i publiczna, nie może zwracać wartości i nie powinna przyjmować żadnego parametru. Ponadto jeśli w metodzie jest używane oczekiwanie asynchroniczne, zwracanym typem musi być typ Task.
+
+
+
+
+ Metoda {0}.{1} ma nieprawidłową sygnaturę. Metoda musi być statyczna i publiczna, nie może zwracać wartości i nie powinna przyjmować pojedynczego parametru typu TestContext. Ponadto jeśli w metodzie jest używane oczekiwanie asynchroniczne, zwracanym typem musi być typ Task.
+
+
+
+
+ UTA054: {0}.{1} ma nieprawidłowy atrybut Timeout. Limit czasu musi być prawidłową liczbą całkowitą i nie może być mniejszy niż 0.
+
+
+
+
+ UTA023: {0}: Nie można zdefiniować wstępnie zdefiniowanej właściwości {2} dla metody {1}.
+
+
+
+
+ UTA022: {0}.{1}: Właściwość niestandardowa „{2}” jest już zdefiniowana. Jako wartość jest używane „{3}”.
+
+
+
+
+ UTA021: {0}: Zerowa lub pusta niestandardowa właściwość została zdefiniowana dla metody {1}. Niestandardowa właściwość musi mieć prawidłową nazwę.
+
+
+
+
+ Metoda {0}.{1} nie istnieje.
+
+
+
+
+ Nie można pobrać domyślnego konstruktora dla klasy {0}.
+
+
+
+
+ Nie można znaleźć właściwości {0}.TestContext. Błąd:{1}.
+
+
+
+
+ Element {0}.TestContext ma niepoprawny typ.
+
+
+
+
+ Metoda {0}.{1} ma nieprawidłową sygnaturę. Metoda musi być niestatyczna i publiczna, nie może zwracać wartości i nie powinna przyjmować żadnego parametru. Ponadto jeśli w metodzie jest używane oczekiwanie asynchroniczne, zwracanym typem musi być typ Task.
+
+
+
+
+ Nie można uzyskać typu {0}. Błąd: {1}.
+
+
+
+
+ Nie znaleziono metody testowej {0}.
+
+
+
+
+ Ślad debugowania:
+
+
+
+
+ Nie powiodło się uzyskanie wyjątku zgłoszonego przez metodę testową {0}.{1}.
+
+
+
+
+ Metoda testowa {0}.{1} zgłosiła wyjątek:
+{2}
+
+
+
+
+ {0} Jeśli w projektach UWP korzystasz z obiektów interfejsu użytkownika podczas testowania, rozważ użycie atrybutu [UITestMethod] zamiast atrybutu [TestMethod], aby wykonywać test w wątku interfejsu użytkownika.
+
+
+
+
+ MSTestAdapterV2
+
+
+
+
+ Nieprawidłowe ustawienia „{0}”. Nieoczekiwany atrybut XmlAttribute: „{1}”.
+
+
+
+
+ Nieprawidłowe ustawienia „{0}”. Nieoczekiwany atrybut XmlElement: „{1}”.
+
+
+
+
+ {0} (wiersz danych {1})
+
+
+
+
+ Atrybut ExpectedException zdefiniowany dla metody testowej {0}.{1} zgłosił wyjątek w trakcie konstruowania.
+{2}
+
+
+
+
+ Metoda testowa {0}.{1} ma wiele zdefiniowanych dla niej atrybutów pochodzących od atrybutu ExpectedExceptionBaseAttribute. Dozwolony jest tylko jeden taki atrybut.
+
+
+
+
+ Ostrzeżenie: Plik testsettings lub plik vsmdi nie jest obsługiwany przez adapter MSTest w wersji 2.
+
+
+
+
+ Komunikaty TestContext:
+
+
+
+
+ Błąd podczas wywoływania metody czyszczącej testu dla klasy testowej {0}: {1}
+
+
+
+
+ Ślad stosu dla TestCleanup
+
+
+
+
+ [MSTest][Discovery][{0}] {1}
+
+
+
+
+ Moduł wykonywania MSTest: włączono obsługę równoległego wykonywania testów dla elementu {0} (procesy robocze: {1}, zakres: {2}).
+
+
+
+
+ Określono nieprawidłową wartość „{0}” dla właściwości „Scope”. Obsługiwane zakresy to {1}.
+ 'Scope' is a setting name that shouldn't be localized.
+
+
+
+ Określono nieprawidłową wartość „{0}” dla właściwości „Workers”. Wartość musi być nieujemną liczbą całkowitą.
+ `Workers` is a setting name that shouldn't be localized.
+
+
+
+ Nie można odnaleźć testów z zestawu {0}. Przyczyna:{1}
+
+
+
+
+ Tylko metody testowe bazujące na danych mogą mieć parametry. Czy chodziło Ci o użycie elementu [DataRow] lub [DynamicData]?
+
+
+
+
+ Wykonanie testu „{0}” zostało przerwane.
+
+
+
+
\ No newline at end of file
diff --git a/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.pt-BR.xlf b/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.pt-BR.xlf
index 6b1245585..795eca5a8 100644
--- a/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.pt-BR.xlf
+++ b/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.pt-BR.xlf
@@ -1,407 +1,343 @@
-
-
-
-
-
-
- Teste '{0}' ultrapassou o período de tempo limite de execução.
-
-
-
-
-
- Não há suporte para execução de teste em qualquer uma das origens fontes fornecidas para a plataforma selecionada
-
-
-
-
-
- O método TestCleanup {0}.{1} gerou exceção. {2}: {3}.
-
-
-
-
-
- --- Fim do rastreamento de pilha de exceção interna ---
-
-
-
-
-
- UTA014: {0}: não é possível definir mais de um método com o atributo AssemblyCleanup em um assembly.
-
-
-
-
-
- UTA013: {0}: não é possível definir mais de um método com o atributo AssemblyInitialize dentro de um assembly.
-
-
-
-
-
- UTA026: {0}: não é possível definir mais de um método com o atributo ClassCleanup dentro de uma classe.
-
-
-
-
-
- UTA025: {0}: não é possível definir mais de um método com o atributo ClassInitialize em uma classe.
-
-
-
-
-
- UTA024: {0}: não é possível definir mais de um método com o atributo TestCleanup.
-
-
-
-
-
- UTA018: {0}: não é possível definir mais de um método com o atributo TestInitialize.
-
-
-
-
-
- O método de inicialização {0}.{1} gerou exceção. {2}.
-
-
-
-
-
- Não é possível criar instância da classe {0}. Erro: {1}.
-
-
-
-
-
- Não é definir a propriedade TestContext para a classe {0}. Erro: {1}.
-
-
-
-
-
- (Falha ao obter a mensagem para uma exceção do tipo {0} devido a uma exceção.)
-
-
-
-
-
- UTA031: classe {0} não tem propriedade TestContext válida. TestContext deve ser de tipo TestContext, deve ser não estático, público e não deve ser somente leitura. Por exemplo: public TestContext TestContext.
-
-
-
-
-
- UTA001: atributo TestClass definido em classe não pública {0}
-
-
-
-
-
- O MSTestAdapter não conseguiu descobrir testes na classe '{0}' do assembly '{1}' devido a {2}.
-
-
-
-
-
- {0}: {1}
-
-
-
-
-
- Não é possível carregar tipos da fonte de teste '{0}'. Alguns ou todos os testes nessa fonte podem não ser descobertos.
-Erro: {1}
-
-
-
-
-
- UTA015: um método genérico não pode ser um método de teste. {0}.{1} tem assinatura inválida
-
-
-
-
-
- O parâmetro não deve ser nulo ou vazio.
-
-
-
-
-
- O parâmetro deve ser maior que zero.
-
-
-
-
-
- MSTestAdapter não conseguiu descobrir testes na classe '{0}' do assembly '{1}'. Motivo {2}.
-
-
-
-
-
- O arquivo não existe: {0}
-
-
-
-
-
- UTA007: o método {1} definido na classe {0} não tem assinatura correta. O método de teste marcado com o atributo [TestMethod] deve ser não estático, público, com tipo de retorno nulo e não deve receber parâmetros. Exemplo: public void Test.Class1.Test(). Adicionalmente, se estiver usando async-await no método de teste então o tipo de retorno deve ser Tarefa. Exemplo: public async Task Test.Class1.Test2()
-
-
-
-
-
- TestContext não pode ser Nulo.
-
-
-
-
-
- Falha no método de Limpeza de Assembly {0}.{1}. Mensagem de Erro: {2}. StackTrace: {3}
-
-
-
-
-
- O método de Inicialização de Assembly {0}.{1} lançou uma exceção. {2}: {3}. Anulando execução de teste.
-
-
-
-
-
- Falha no método de Limpeza de Classe {0}.{1}. Mensagem de Erro: {2}. Rastreamento de Pilha: {3}
-
-
-
-
-
- O método de Inicialização de Classe {0}.{1} lançou uma exceção. {2}: {3}.
-
-
-
-
-
- Exceção lançada durante a execução do teste. Se usar a extensão de TestMethodAttribute, entre em contato com o fornecedor. Mensagem de erro: {0}
-
-
-
-
-
- Erro ao executar o teste. Nenhum resultado retornado pela extensão. Se usar a extensão de TestMethodAttribute, entre em contato com o fornecedor.
-
-
-
-
-
- O método {0}.{1} tem assinatura incorreta. O método deve ser estático, público, não deve retornar um valor nem receber parâmetro. Além disso, se estiver usando async-await no método, return-type deverá ser Task.
-
-
-
-
-
- O método {0}.{1} tem assinatura incorreta. O método deve ser estático, público, não deve retornar um valor e deve receber um único parâmetro do tipo TestContext. Além disso, se estiver usando async-await no método, return-type deverá ser Task.
-
-
-
-
-
- UTA054: {0}.{1} tem atributo Timeout inválido. O tempo limite deve ser um valor inteiro válido e não pode ser menor que 0.
-
-
-
-
-
- UTA023: {0}: não é possível definir a propriedade predefinida {2} no método {1}.
-
-
-
-
-
- UTA022: {0}.{1}: A propriedade personalizada "{2}" já está definida. Usando "{3}" como valor.
-
-
-
-
-
- UTA021: {0}: Propriedade personalizada nula ou vazia definida no método {1}. A propriedade personalizada deve ter um nome válido.
-
-
-
-
-
- O método {0}.{1} não existe.
-
-
-
-
-
- Não é possível obter o construtor padrão para a classe {0}.
-
-
-
-
-
- Não é possível encontrar propriedade {0}.TestContext. Erro:{1}.
-
-
-
-
-
- O {0}.TestContext é do tipo incorreto.
-
-
-
-
-
- O método {0}.{1} tem assinatura incorreta. O método deve ser não estático, público, não deve retornar um valor e não deve receber nenhum parâmetro. Além disso, se você estiver usando um async-await no método, então return-type deverá ser Task.
-
-
-
-
-
- Não é possível obter o tipo {0}. Erro: {1}.
-
-
-
-
-
- O método de teste {0} não foi encontrado.
-
-
-
-
-
- Rastreamento de Depuração:
-
-
-
-
-
- Falha ao obter a exceção lançada pelo método de teste {0}.{1}.
-
-
-
-
-
- O método de teste {0}.{1} lançou a exceção:
-{2}
-
-
-
-
-
- {0} Para projetos UWP, se você está usando objetos de IU no teste, considere usar o atributo [UITestMethod] em vez de [TestMethod] para executar o teste no thread da IU.
-
-
-
-
-
- MSTestAdapterV2
-
-
-
-
-
- Configurações inválidas '{0}'. XmlAttribute inesperado: '{1}'.
-
-
-
-
-
- Configurações inválidas '{0}'. XmlElement inesperado: '{1}'.
-
-
-
-
-
- {0} (Linha de Dados {1})
-
-
-
-
-
- O atributo ExpectedException definido no método de teste {0}.{1} emitiu uma exceção durante a construção.
-{2}
-
-
-
-
-
- O método de teste {0}.{1} tem vários atributos derivados de ExpectedExceptionBaseAttribute definidos nele. Somente um atributo é permitido.
-
-
-
-
-
- Aviso: um arquivo testsettings ou um arquivo vsmdi não tem suporte no MSTest V2 Adapter.
-
-
-
-
-
- Mensagens TestContext:
-
-
-
-
-
- Erro ao chamar o método Test Cleanup para a classe de teste {0}: {1}
-
-
-
-
-
- Rastreamento de pilha TestCleanup
-
-
-
-
-
- [MSTest][Descoberta][{0}] {1}
-
-
-
-
-
- MSTest Executor: paralelização de teste habilitada para {0} (Workers: {1}, Scope: {2}).
-
-
-
-
-
- Valor inválido '{0}' especificado para 'Scope'. Os escopos compatíveis são {1}.
- 'Scope' is a setting name that shouldn't be localized.
-
-
-
- Valor inválido '{0}' especificado para 'Workers'. O valor deve ser um inteiro não negativo.
- `Workers` is a setting name that shouldn't be localized.
-
-
-
- Falha ao descobrir testes por meio do assembly {0}. Motivo: {1}
-
-
-
-
-
- Apenas os métodos de teste controlados por dados podem ter parâmetros. Você pretendia usar [DataRow] ou [DynamicData]?
-
-
-
-
-
- A execução do teste '{0}' foi anulada.
-
-
-
-
-
+
+
+
+
+
+
+ Teste '{0}' ultrapassou o período de tempo limite de execução.
+
+
+
+
+ Não há suporte para execução de teste em qualquer uma das origens fontes fornecidas para a plataforma selecionada
+
+
+
+
+ O método TestCleanup {0}.{1} gerou exceção. {2}: {3}.
+
+
+
+
+ --- Fim do rastreamento de pilha de exceção interna ---
+
+
+
+
+ UTA014: {0}: não é possível definir mais de um método com o atributo AssemblyCleanup em um assembly.
+
+
+
+
+ UTA013: {0}: não é possível definir mais de um método com o atributo AssemblyInitialize dentro de um assembly.
+
+
+
+
+ UTA026: {0}: não é possível definir mais de um método com o atributo ClassCleanup dentro de uma classe.
+
+
+
+
+ UTA025: {0}: não é possível definir mais de um método com o atributo ClassInitialize em uma classe.
+
+
+
+
+ UTA024: {0}: não é possível definir mais de um método com o atributo TestCleanup.
+
+
+
+
+ UTA018: {0}: não é possível definir mais de um método com o atributo TestInitialize.
+
+
+
+
+ O método de inicialização {0}.{1} gerou exceção. {2}.
+
+
+
+
+ Não é possível criar instância da classe {0}. Erro: {1}.
+
+
+
+
+ Não é definir a propriedade TestContext para a classe {0}. Erro: {1}.
+
+
+
+
+ (Falha ao obter a mensagem para uma exceção do tipo {0} devido a uma exceção.)
+
+
+
+
+ UTA031: classe {0} não tem propriedade TestContext válida. TestContext deve ser de tipo TestContext, deve ser não estático, público e não deve ser somente leitura. Por exemplo: public TestContext TestContext.
+
+
+
+
+ UTA001: atributo TestClass definido em classe não pública {0}
+
+
+
+
+ O MSTestAdapter não conseguiu descobrir testes na classe '{0}' do assembly '{1}' devido a {2}.
+
+
+
+
+ {0}: {1}
+
+
+
+
+ Não é possível carregar tipos da fonte de teste '{0}'. Alguns ou todos os testes nessa fonte podem não ser descobertos.
+Erro: {1}
+
+
+
+
+ UTA015: um método genérico não pode ser um método de teste. {0}.{1} tem assinatura inválida
+
+
+
+
+ O parâmetro não deve ser nulo ou vazio.
+
+
+
+
+ O parâmetro deve ser maior que zero.
+
+
+
+
+ MSTestAdapter não conseguiu descobrir testes na classe '{0}' do assembly '{1}'. Motivo {2}.
+
+
+
+
+ O arquivo não existe: {0}
+
+
+
+
+ UTA007: o método {1} definido na classe {0} não tem assinatura correta. O método de teste marcado com o atributo [TestMethod] deve ser não estático, público, com tipo de retorno nulo e não deve receber parâmetros. Exemplo: public void Test.Class1.Test(). Adicionalmente, se estiver usando async-await no método de teste então o tipo de retorno deve ser Tarefa. Exemplo: public async Task Test.Class1.Test2()
+
+
+
+
+ TestContext não pode ser Nulo.
+
+
+
+
+ Falha no método de Limpeza de Assembly {0}.{1}. Mensagem de Erro: {2}. StackTrace: {3}
+
+
+
+
+ O método de Inicialização de Assembly {0}.{1} lançou uma exceção. {2}: {3}. Anulando execução de teste.
+
+
+
+
+ Falha no método de Limpeza de Classe {0}.{1}. Mensagem de Erro: {2}. Rastreamento de Pilha: {3}
+
+
+
+
+ O método de Inicialização de Classe {0}.{1} lançou uma exceção. {2}: {3}.
+
+
+
+
+ Exceção lançada durante a execução do teste. Se usar a extensão de TestMethodAttribute, entre em contato com o fornecedor. Mensagem de erro: {0}
+
+
+
+
+ Erro ao executar o teste. Nenhum resultado retornado pela extensão. Se usar a extensão de TestMethodAttribute, entre em contato com o fornecedor.
+
+
+
+
+ O método {0}.{1} tem assinatura incorreta. O método deve ser estático, público, não deve retornar um valor nem receber parâmetro. Além disso, se estiver usando async-await no método, return-type deverá ser Task.
+
+
+
+
+ O método {0}.{1} tem assinatura incorreta. O método deve ser estático, público, não deve retornar um valor e deve receber um único parâmetro do tipo TestContext. Além disso, se estiver usando async-await no método, return-type deverá ser Task.
+
+
+
+
+ UTA054: {0}.{1} tem atributo Timeout inválido. O tempo limite deve ser um valor inteiro válido e não pode ser menor que 0.
+
+
+
+
+ UTA023: {0}: não é possível definir a propriedade predefinida {2} no método {1}.
+
+
+
+
+ UTA022: {0}.{1}: A propriedade personalizada "{2}" já está definida. Usando "{3}" como valor.
+
+
+
+
+ UTA021: {0}: Propriedade personalizada nula ou vazia definida no método {1}. A propriedade personalizada deve ter um nome válido.
+
+
+
+
+ O método {0}.{1} não existe.
+
+
+
+
+ Não é possível obter o construtor padrão para a classe {0}.
+
+
+
+
+ Não é possível encontrar propriedade {0}.TestContext. Erro:{1}.
+
+
+
+
+ O {0}.TestContext é do tipo incorreto.
+
+
+
+
+ O método {0}.{1} tem assinatura incorreta. O método deve ser não estático, público, não deve retornar um valor e não deve receber nenhum parâmetro. Além disso, se você estiver usando um async-await no método, então return-type deverá ser Task.
+
+
+
+
+ Não é possível obter o tipo {0}. Erro: {1}.
+
+
+
+
+ O método de teste {0} não foi encontrado.
+
+
+
+
+ Rastreamento de Depuração:
+
+
+
+
+ Falha ao obter a exceção lançada pelo método de teste {0}.{1}.
+
+
+
+
+ O método de teste {0}.{1} lançou a exceção:
+{2}
+
+
+
+
+ {0} Para projetos UWP, se você está usando objetos de IU no teste, considere usar o atributo [UITestMethod] em vez de [TestMethod] para executar o teste no thread da IU.
+
+
+
+
+ MSTestAdapterV2
+
+
+
+
+ Configurações inválidas '{0}'. XmlAttribute inesperado: '{1}'.
+
+
+
+
+ Configurações inválidas '{0}'. XmlElement inesperado: '{1}'.
+
+
+
+
+ {0} (Linha de Dados {1})
+
+
+
+
+ O atributo ExpectedException definido no método de teste {0}.{1} emitiu uma exceção durante a construção.
+{2}
+
+
+
+
+ O método de teste {0}.{1} tem vários atributos derivados de ExpectedExceptionBaseAttribute definidos nele. Somente um atributo é permitido.
+
+
+
+
+ Aviso: um arquivo testsettings ou um arquivo vsmdi não tem suporte no MSTest V2 Adapter.
+
+
+
+
+ Mensagens TestContext:
+
+
+
+
+ Erro ao chamar o método Test Cleanup para a classe de teste {0}: {1}
+
+
+
+
+ Rastreamento de pilha TestCleanup
+
+
+
+
+ [MSTest][Descoberta][{0}] {1}
+
+
+
+
+ MSTest Executor: paralelização de teste habilitada para {0} (Workers: {1}, Scope: {2}).
+
+
+
+
+ Valor inválido '{0}' especificado para 'Scope'. Os escopos compatíveis são {1}.
+ 'Scope' is a setting name that shouldn't be localized.
+
+
+
+ Valor inválido '{0}' especificado para 'Workers'. O valor deve ser um inteiro não negativo.
+ `Workers` is a setting name that shouldn't be localized.
+
+
+
+ Falha ao descobrir testes por meio do assembly {0}. Motivo: {1}
+
+
+
+
+ Apenas os métodos de teste controlados por dados podem ter parâmetros. Você pretendia usar [DataRow] ou [DynamicData]?
+
+
+
+
+ A execução do teste '{0}' foi anulada.
+
+
+
+
\ No newline at end of file
diff --git a/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.ru.xlf b/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.ru.xlf
index 73891d57b..f37f6892a 100644
--- a/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.ru.xlf
+++ b/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.ru.xlf
@@ -1,407 +1,343 @@
-
-
-
-
-
-
- Превышено время ожидания выполнения теста "{0}".
-
-
-
-
-
- Запуск тестов в любом из предоставленных источников не поддерживается на выбранной платформе
-
-
-
-
-
- Метод TestCleanup {0}.{1} вызвал исключение. {2}: {3}.
-
-
-
-
-
- --- Конец трассировки стека внутренних исключений ---
-
-
-
-
-
- UTA014: {0}: в сборке невозможно определить несколько методов с атрибутом AssemblyCleanup.
-
-
-
-
-
- UTA013: {0}: в сборке невозможно определить несколько методов с атрибутом AssemblyInitialize.
-
-
-
-
-
- UTA026: {0}: в классе невозможно определить несколько методов с атрибутом ClassCleanup.
-
-
-
-
-
- UTA025: {0}: в классе невозможно определить несколько методов с атрибутом ClassInitialize.
-
-
-
-
-
- UTA024: {0}: невозможно определить несколько методов с атрибутом TestCleanup.
-
-
-
-
-
- UTA018: {0}: невозможно определить несколько методов с атрибутом TestInitialize.
-
-
-
-
-
- Метод инициализации {0}.{1} вызвал исключение. {2}.
-
-
-
-
-
- Не удалось создать экземпляр класса {0}. Ошибка: {1}.
-
-
-
-
-
- Не удалось задать свойство TestContext для класса {0}. Ошибка: {1}.
-
-
-
-
-
- (Не удалось получить сообщение для исключения с типом {0} в связи с возникновением исключения.)
-
-
-
-
-
- UTA031: в классе {0} отсутствует допустимое свойство TestContext. Свойство TestContext должно иметь тип TestContext, быть нестатическим, открытым и не должно быть предназначено только для чтения. Например: public TestContext TestContext.
-
-
-
-
-
- UTA001: атрибут TestClass определен в классе {0}, не являющемся открытым
-
-
-
-
-
- Средству MSTestAdapter не удалось обнаружить тесты в классе "{0}" сборки "{1}", так как {2}.
-
-
-
-
-
- {0}: {1}
-
-
-
-
-
- Не удалось загрузить типы из тестового источника "{0}". В этом источнике могут быть не обнаружены некоторые или все тесты.
-Ошибка: {1}
-
-
-
-
-
- UTA015: универсальный метод не может быть методом теста. {0}.{1} имеет недопустимую сигнатуру
-
-
-
-
-
- Этот параметр не должен быть пустым или иметь значение NULL.
-
-
-
-
-
- Этот параметр должен быть больше нуля.
-
-
-
-
-
- Средству MSTestAdapter не удалось обнаружить тесты в классе "{0}" сборки "{1}". Причина: {2}.
-
-
-
-
-
- Файл не существует: {0}
-
-
-
-
-
- UTA007: метод {1}, определенный в классе {0}, имеет неправильную сигнатуру. Метод теста, помеченный атрибутом [TestMethod], должен быть нестатическим, открытым и иметь тип возвращаемого значения void; он также не должен принимать параметры. Пример: public void Test.Class1.Test(). Кроме того, если вы используете модификатор async-await в методе теста, тип возвращаемого значения должен быть Task. Пример: public async Task Test.Class1.Test2()
-
-
-
-
-
- TestContext не может иметь значение NULL.
-
-
-
-
-
- Не удалось применить метод очистки сборки {0}.{1}. Сообщение об ошибке: {2}. Трассировка стека (StackTrace): {3}.
-
-
-
-
-
- Методом инициализации сборки {0}.{1} создано исключение. {2}: {3}. Выполнение теста прекращается.
-
-
-
-
-
- Не удалось применить метод очистки класса {0}.{1}. Сообщение об ошибке: {2}. Трассировка стека: {3}.
-
-
-
-
-
- Методом инициализации класса {0}.{1} создано исключение. {2}: {3}.
-
-
-
-
-
- При выполнении теста возникло исключение. Если используется расширение атрибута TestMethodAttribute, обратитесь к поставщику. Сообщение об ошибке: {0}.
-
-
-
-
-
- Ошибка при выполнении теста. Расширение не возвратило результаты. Если используется расширение атрибута TestMethodAttribute, обратитесь к поставщику.
-
-
-
-
-
- Метод {0}.{1} имеет неправильную сигнатуру. Метод должен быть статическим и открытым, не должен возвращать значение и принимать параметры. Кроме того, при использовании в методе async-await возвращаемое значение должно иметь тип Task.
-
-
-
-
-
- Метод {0}.{1} имеет неправильную сигнатуру. Метод должен быть статическим и открытым, не должен возвращать значение и должен принимать один параметр, имеющий тип TestContext. Кроме того, при использовании в методе async-await возвращаемое значение должно иметь тип Task.
-
-
-
-
-
- UTA054: {0}.{1} имеет недопустимый атрибут Timeout. Время ожидания должно быть допустимым целым числом и не может быть меньше 0.
-
-
-
-
-
- UTA023: {0}: не удается определить предопределенное свойство {2} в методе {1}.
-
-
-
-
-
- UTA022: {0}.{1}: пользовательское свойство "{2}" уже определено. В качестве значения используется "{3}".
-
-
-
-
-
- UTA021: {0}: в методе {1} определено пользовательское свойство, имя которого имеет значение NULL или пусто. Пользовательское свойство должно иметь допустимое имя.
-
-
-
-
-
- Метод {0}.{1} не существует.
-
-
-
-
-
- Не удается получить конструктор по умолчанию для класса {0}.
-
-
-
-
-
- Не удается найти свойство {0}.TestContext. Ошибка: {1}.
-
-
-
-
-
- Для свойства {0}.TestContext указан неправильный тип.
-
-
-
-
-
- Метод {0}.{1} имеет неправильную сигнатуру. Метод должен быть нестатическим и открытым, не должен возвращать значение и принимать параметры. Кроме того, при использовании в методе async-await возвращаемое значение должно иметь тип Task.
-
-
-
-
-
- Не удается получить тип {0}. Ошибка: {1}.
-
-
-
-
-
- Метод теста {0} не найден.
-
-
-
-
-
- Трассировка отладки:
-
-
-
-
-
- Не удалось получить исключение, созданное методом теста {0}.{1}.
-
-
-
-
-
- Метод теста {0}.{1} создал исключение:
-{2}.
-
-
-
-
-
- {0} В проектах UWP, если в тесте используются объекты пользовательского интерфейса, рассмотрите возможность использования атрибута [UITestMethod] вместо атрибута [TestMethod] для выполнения теста в потоке пользовательского интерфейса.
-
-
-
-
-
- MSTestAdapterV2
-
-
-
-
-
- Недопустимые параметры "{0}". Непредвиденный атрибут XmlAttribute: "{1}".
-
-
-
-
-
- Недопустимые параметры "{0}". Непредвиденный элемент XmlElement: "{1}".
-
-
-
-
-
- {0} (строка данных {1})
-
-
-
-
-
- Атрибут ExpectedException, определенный в методе теста {0}.{1}, породил исключение во время создания.
-{2}
-
-
-
-
-
- В методе теста {0}.{1} определено несколько атрибутов, производных от ExpectedExceptionBaseAttribute, заданного в нем. Допускается только один такой атрибут.
-
-
-
-
-
- Внимание! Адаптер MSTest версии 2 не поддерживает файл TESTSETTINGS или VSMDI.
-
-
-
-
-
- Сообщения TestContext:
-
-
-
-
-
- Ошибка при вызове метода TestCleanup для тестового класса {0}: {1}
-
-
-
-
-
- Трассировка стека TestCleanup
-
-
-
-
-
- [MSTest][Discovery][{0}] {1}
-
-
-
-
-
- Исполнитель MSTest: включена параллелизация тестов для {0} (рабочие роли: {1}, область: {2}).
-
-
-
-
-
- В поле "Область" указано недопустимое значение "{0}". Поддерживаемые области: {1}.
- 'Scope' is a setting name that shouldn't be localized.
-
-
-
- В поле "Рабочие роли" указано недопустимое значение "{0}". Оно должно быть неотрицательным целым числом.
- `Workers` is a setting name that shouldn't be localized.
-
-
-
- Не удалось обнаружить тесты из сборки {0}. Причина:{1}
-
-
-
-
-
- Только методы теста, управляемые данными, могут иметь параметры. Вы планировали использовать [DataRow] или [DynamicData]?
-
-
-
-
-
- Выполнение теста "{0}" было прервано.
-
-
-
-
-
+
+
+
+
+
+
+ Превышено время ожидания выполнения теста "{0}".
+
+
+
+
+ Запуск тестов в любом из предоставленных источников не поддерживается на выбранной платформе
+
+
+
+
+ Метод TestCleanup {0}.{1} вызвал исключение. {2}: {3}.
+
+
+
+
+ --- Конец трассировки стека внутренних исключений ---
+
+
+
+
+ UTA014: {0}: в сборке невозможно определить несколько методов с атрибутом AssemblyCleanup.
+
+
+
+
+ UTA013: {0}: в сборке невозможно определить несколько методов с атрибутом AssemblyInitialize.
+
+
+
+
+ UTA026: {0}: в классе невозможно определить несколько методов с атрибутом ClassCleanup.
+
+
+
+
+ UTA025: {0}: в классе невозможно определить несколько методов с атрибутом ClassInitialize.
+
+
+
+
+ UTA024: {0}: невозможно определить несколько методов с атрибутом TestCleanup.
+
+
+
+
+ UTA018: {0}: невозможно определить несколько методов с атрибутом TestInitialize.
+
+
+
+
+ Метод инициализации {0}.{1} вызвал исключение. {2}.
+
+
+
+
+ Не удалось создать экземпляр класса {0}. Ошибка: {1}.
+
+
+
+
+ Не удалось задать свойство TestContext для класса {0}. Ошибка: {1}.
+
+
+
+
+ (Не удалось получить сообщение для исключения с типом {0} в связи с возникновением исключения.)
+
+
+
+
+ UTA031: в классе {0} отсутствует допустимое свойство TestContext. Свойство TestContext должно иметь тип TestContext, быть нестатическим, открытым и не должно быть предназначено только для чтения. Например: public TestContext TestContext.
+
+
+
+
+ UTA001: атрибут TestClass определен в классе {0}, не являющемся открытым
+
+
+
+
+ Средству MSTestAdapter не удалось обнаружить тесты в классе "{0}" сборки "{1}", так как {2}.
+
+
+
+
+ {0}: {1}
+
+
+
+
+ Не удалось загрузить типы из тестового источника "{0}". В этом источнике могут быть не обнаружены некоторые или все тесты.
+Ошибка: {1}
+
+
+
+
+ UTA015: универсальный метод не может быть методом теста. {0}.{1} имеет недопустимую сигнатуру
+
+
+
+
+ Этот параметр не должен быть пустым или иметь значение NULL.
+
+
+
+
+ Этот параметр должен быть больше нуля.
+
+
+
+
+ Средству MSTestAdapter не удалось обнаружить тесты в классе "{0}" сборки "{1}". Причина: {2}.
+
+
+
+
+ Файл не существует: {0}
+
+
+
+
+ UTA007: метод {1}, определенный в классе {0}, имеет неправильную сигнатуру. Метод теста, помеченный атрибутом [TestMethod], должен быть нестатическим, открытым и иметь тип возвращаемого значения void; он также не должен принимать параметры. Пример: public void Test.Class1.Test(). Кроме того, если вы используете модификатор async-await в методе теста, тип возвращаемого значения должен быть Task. Пример: public async Task Test.Class1.Test2()
+
+
+
+
+ TestContext не может иметь значение NULL.
+
+
+
+
+ Не удалось применить метод очистки сборки {0}.{1}. Сообщение об ошибке: {2}. Трассировка стека (StackTrace): {3}.
+
+
+
+
+ Методом инициализации сборки {0}.{1} создано исключение. {2}: {3}. Выполнение теста прекращается.
+
+
+
+
+ Не удалось применить метод очистки класса {0}.{1}. Сообщение об ошибке: {2}. Трассировка стека: {3}.
+
+
+
+
+ Методом инициализации класса {0}.{1} создано исключение. {2}: {3}.
+
+
+
+
+ При выполнении теста возникло исключение. Если используется расширение атрибута TestMethodAttribute, обратитесь к поставщику. Сообщение об ошибке: {0}.
+
+
+
+
+ Ошибка при выполнении теста. Расширение не возвратило результаты. Если используется расширение атрибута TestMethodAttribute, обратитесь к поставщику.
+
+
+
+
+ Метод {0}.{1} имеет неправильную сигнатуру. Метод должен быть статическим и открытым, не должен возвращать значение и принимать параметры. Кроме того, при использовании в методе async-await возвращаемое значение должно иметь тип Task.
+
+
+
+
+ Метод {0}.{1} имеет неправильную сигнатуру. Метод должен быть статическим и открытым, не должен возвращать значение и должен принимать один параметр, имеющий тип TestContext. Кроме того, при использовании в методе async-await возвращаемое значение должно иметь тип Task.
+
+
+
+
+ UTA054: {0}.{1} имеет недопустимый атрибут Timeout. Время ожидания должно быть допустимым целым числом и не может быть меньше 0.
+
+
+
+
+ UTA023: {0}: не удается определить предопределенное свойство {2} в методе {1}.
+
+
+
+
+ UTA022: {0}.{1}: пользовательское свойство "{2}" уже определено. В качестве значения используется "{3}".
+
+
+
+
+ UTA021: {0}: в методе {1} определено пользовательское свойство, имя которого имеет значение NULL или пусто. Пользовательское свойство должно иметь допустимое имя.
+
+
+
+
+ Метод {0}.{1} не существует.
+
+
+
+
+ Не удается получить конструктор по умолчанию для класса {0}.
+
+
+
+
+ Не удается найти свойство {0}.TestContext. Ошибка: {1}.
+
+
+
+
+ Для свойства {0}.TestContext указан неправильный тип.
+
+
+
+
+ Метод {0}.{1} имеет неправильную сигнатуру. Метод должен быть нестатическим и открытым, не должен возвращать значение и принимать параметры. Кроме того, при использовании в методе async-await возвращаемое значение должно иметь тип Task.
+
+
+
+
+ Не удается получить тип {0}. Ошибка: {1}.
+
+
+
+
+ Метод теста {0} не найден.
+
+
+
+
+ Трассировка отладки:
+
+
+
+
+ Не удалось получить исключение, созданное методом теста {0}.{1}.
+
+
+
+
+ Метод теста {0}.{1} создал исключение:
+{2}.
+
+
+
+
+ {0} В проектах UWP, если в тесте используются объекты пользовательского интерфейса, рассмотрите возможность использования атрибута [UITestMethod] вместо атрибута [TestMethod] для выполнения теста в потоке пользовательского интерфейса.
+
+
+
+
+ MSTestAdapterV2
+
+
+
+
+ Недопустимые параметры "{0}". Непредвиденный атрибут XmlAttribute: "{1}".
+
+
+
+
+ Недопустимые параметры "{0}". Непредвиденный элемент XmlElement: "{1}".
+
+
+
+
+ {0} (строка данных {1})
+
+
+
+
+ Атрибут ExpectedException, определенный в методе теста {0}.{1}, породил исключение во время создания.
+{2}
+
+
+
+
+ В методе теста {0}.{1} определено несколько атрибутов, производных от ExpectedExceptionBaseAttribute, заданного в нем. Допускается только один такой атрибут.
+
+
+
+
+ Внимание! Адаптер MSTest версии 2 не поддерживает файл TESTSETTINGS или VSMDI.
+
+
+
+
+ Сообщения TestContext:
+
+
+
+
+ Ошибка при вызове метода TestCleanup для тестового класса {0}: {1}
+
+
+
+
+ Трассировка стека TestCleanup
+
+
+
+
+ [MSTest][Discovery][{0}] {1}
+
+
+
+
+ Исполнитель MSTest: включена параллелизация тестов для {0} (рабочие роли: {1}, область: {2}).
+
+
+
+
+ В поле "Область" указано недопустимое значение "{0}". Поддерживаемые области: {1}.
+ 'Scope' is a setting name that shouldn't be localized.
+
+
+
+ В поле "Рабочие роли" указано недопустимое значение "{0}". Оно должно быть неотрицательным целым числом.
+ `Workers` is a setting name that shouldn't be localized.
+
+
+
+ Не удалось обнаружить тесты из сборки {0}. Причина:{1}
+
+
+
+
+ Только методы теста, управляемые данными, могут иметь параметры. Вы планировали использовать [DataRow] или [DynamicData]?
+
+
+
+
+ Выполнение теста "{0}" было прервано.
+
+
+
+
\ No newline at end of file
diff --git a/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.tr.xlf b/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.tr.xlf
index 205021e36..3906031eb 100644
--- a/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.tr.xlf
+++ b/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.tr.xlf
@@ -1,407 +1,343 @@
-
-
-
-
-
-
- '{0}' testi yürütme zaman aşımı süresini aştı.
-
-
-
-
-
- Testlerin sağlanan kaynakların herhangi birinde çalıştırılması seçili platformda desteklenmiyor
-
-
-
-
-
- TestCleanup metodu ({0}.{1}) özel durum oluşturdu. {2}: {3}.
-
-
-
-
-
- --- İç özel durum yığın izlemesinin sonu ---
-
-
-
-
-
- UTA014: {0}: Bir bütünleştirilmiş kod içinde AssemblyCleanup özniteliği ile birden fazla metot tanımlanamaz.
-
-
-
-
-
- UTA013: {0}: Bir bütünleştirilmiş kod içinde AssemblyInitialize özniteliği ile birden fazla metot tanımlanamaz.
-
-
-
-
-
- UTA026: {0}: Bir sınıf içinde ClassCleanup özniteliği ile birden fazla metot tanımlanamaz.
-
-
-
-
-
- UTA025: {0}: Bir sınıf içinde ClassInitialize özniteliği ile birden fazla metot tanımlanamaz.
-
-
-
-
-
- UTA024: {0}: TestCleanup özniteliği ile birden fazla metot tanımlanamaz.
-
-
-
-
-
- UTA018: {0}: TestInitialize özniteliği ile birden fazla metot tanımlanamaz.
-
-
-
-
-
- Başlatma metodu {0}.{1} özel durum oluşturdu. {2}.
-
-
-
-
-
- {0} sınıfının örneği oluşturulamıyor. Hata: {1}.
-
-
-
-
-
- {0} sınıfı için TestContext özelliği ayarlanamıyor. Hata: {1}.
-
-
-
-
-
- (Bir özel durum nedeniyle, {0} türündeki özel durum iletisi alınamadı.)
-
-
-
-
-
- UTA031: {0} sınıfı geçerli bir TestContext özelliğine sahip değil. TestContext, TestContext türünde olmalı, statik olmamalı, genel olmalı ve salt okunur olmamalı. Örnek: public TestContext TestContext.
-
-
-
-
-
- UTA001: TestClass özniteliği genel olmayan {0} sınıfında tanımlanmış
-
-
-
-
-
- MSTestAdapter, '{1}' bütünleştirilmiş kodunun '{0}' sınıfındaki testleri bulamadı. Nedeni: {2}.
-
-
-
-
-
- {0}: {1}
-
-
-
-
-
- '{0}' test kaynağından türler yüklenemiyor. Kaynaktaki testlerin bazıları veya tümü bulunamayabilir.
-Hata: {1}
-
-
-
-
-
- UTA015: Genel metot bir test metodu olamaz. {0}.{1} geçersiz imzaya sahip
-
-
-
-
-
- Parametre null veya boş olmamalıdır.
-
-
-
-
-
- Parametre sıfırdan büyük olmalıdır.
-
-
-
-
-
- MSTestAdapter, '{1}' bütünleştirilmiş kodunun '{0}' sınıfında testleri bulamadı. Nedeni: {2}.
-
-
-
-
-
- Dosya yok: {0}
-
-
-
-
-
- UTA007: {0} sınıfında tanımlanan {1} metodunun imzası doğru değil. [TestMethod] özniteliğiyle işaretlenen test metodu statik olmamalı, genel olmalı, return-type değeri void olmalı ve hiçbir parametre almamalıdır. Örnek: public void Test.Class1.Test(). Bunlara ek olarak, test metodunda async-await kullanıyorsanız return-type değeri Task olmalıdır. Örnek: public async Task Test.Class1.Test2()
-
-
-
-
-
- TestContext, Null olamaz.
-
-
-
-
-
- Bütünleştirilmiş Kod Temizleme metodu ({0}.{1}) başarısız oldu. Hata İletisi: {2}. StackTrace: {3}
-
-
-
-
-
- Bütünleştirilmiş Kod Başlatma metodu ({0}.{1}) özel durum oluşturdu. {2}: {3}. Test yürütmesi durduruluyor.
-
-
-
-
-
- Sınıf Temizleme metodu ({0}.{1}) başarısız oldu. Hata İletisi: {2}. Yığın İzlemesi: {3}
-
-
-
-
-
- Sınıf Başlatma metodu ({0}.{1}) özel durum oluşturdu. {2}: {3}.
-
-
-
-
-
- Test yürütülürken özel durum oluşturuldu. TestMethodAttribute uzantısı kullanılıyorsa, lütfen satıcıya başvurun. Hata iletisi: {0}
-
-
-
-
-
- Test yürütülürken hata oluştu. Uzantı tarafından hiç sonuç döndürülmedi. TestMethodAttribute uzantısı kullanılıyorsa, lütfen satıcıya başvurun.
-
-
-
-
-
- {0}.{1} metodunun imzası yanlış. Metot statik, genel, değer döndürmeyen bir metot olmalı, hiçbir parametre almamalıdır. Bunlara ek olarak, metotta async-await kullanıyorsanız return-type değeri Task olmalıdır.
-
-
-
-
-
- {0}.{1} metodunun imzası yanlış. Metot statik, genel, değer döndürmeyen bir metot olmalı ve TestContext türünde tek bir parametre almalıdır. Bunlara ek olarak, metotta async-await kullanıyorsanız return-type değeri Task olmalıdır.
-
-
-
-
-
- UTA054: {0}.{1} geçersiz Timeout özniteliğine sahip. Zaman aşımı geçerli bir tamsayı değer olmalıdır ve 0'dan küçük olamaz.
-
-
-
-
-
- UTA023: {0}: Önceden tanımlanmış {2} özelliği {1} metodunda tanımlanamaz.
-
-
-
-
-
- UTA022: {0}.{1}: "{2}" özel özelliği zaten tanımlanmış. Değer olarak "{3}" kullanılıyor.
-
-
-
-
-
- UTA021: {0}: {1} metodunda null veya boş özel özellik tanımlanmış. Özel özellik geçerli bir ada sahip olmalıdır.
-
-
-
-
-
- {0}.{1} metodu yok.
-
-
-
-
-
- {0} sınıfı için varsayılan oluşturucu alınamıyor.
-
-
-
-
-
- {0}.TestContext özelliği bulunamıyor. Hata:{1}.
-
-
-
-
-
- {0}.TestContext yanlış türe sahip.
-
-
-
-
-
- {0}.{1} metodunun imzası yanlış. Metot statik olmayan, genel, değer döndürmeyen bir metot olmalı, hiçbir parametre almamalıdır. Bunlara ek olarak, metotta async-await kullanıyorsanız return-type değeri Task olmalıdır.
-
-
-
-
-
- {0} türü alınamıyor. Hata: {1}.
-
-
-
-
-
- {0} test metodu bulunamadı.
-
-
-
-
-
- Hata Ayıklama İzleyici:
-
-
-
-
-
- {0}.{1} metodu tarafından oluşturulan özel durum alınamadı.
-
-
-
-
-
- {0}.{1} test metodu özel durum oluşturdu:
-{2}
-
-
-
-
-
- {0} UWP projeleri için testte UI nesneleri kullanıyorsanız, testi UI iş parçacığında yürütmek için [TestMethod] yerine [UITestMethod] özniteliğini kullanabilirsiniz.
-
-
-
-
-
- MSTestAdapterV2
-
-
-
-
-
- Geçersiz '{0}' ayarları. Beklenmeyen XmlAttribute: '{1}'.
-
-
-
-
-
- Geçersiz '{0}' ayarları. Beklenmeyen XmlElement: '{1}'.
-
-
-
-
-
- {0} (Veri Satırı {1})
-
-
-
-
-
- {0}.{1} test yöntemi üzerinde tanımlanan ExpectedException özniteliği, oluşturma sırasında bir özel durum oluşturdu.
-{2}
-
-
-
-
-
- {0}.{1} test yöntemi, üzerinde tanımlanan ExpectedExceptionBaseAttribute öğesinden türetilmiş birden fazla öznitelik içeriyor. Bu türde yalnızca bir tane özniteliğe izin verilir.
-
-
-
-
-
- Uyarı : MSTest V2 Adapter ile bir testsettings dosyası veya bir vsmdi dosyası desteklenmez.
-
-
-
-
-
- TestContext İletileri:
-
-
-
-
-
- {0} test sınıfı için Test Temizleme metodu çağrılırken hata oluştu: {1}
-
-
-
-
-
- TestCleanup Yığın İzleme
-
-
-
-
-
- [MSTest][Discovery][{0}] {1}
-
-
-
-
-
- MSTest Yürütücü: {0} için Test Paralelleştirme etkin (Workers: {1}, Scope: {2}).
-
-
-
-
-
- 'Scope' için geçersiz '{0}' değeri belirtildi. Desteklenen kapsamlar {1}.
- 'Scope' is a setting name that shouldn't be localized.
-
-
-
- 'Workers' için geçersiz '{0}' değeri belirtildi. Değer negatif olmayan bir tamsayı olmalıdır.
- `Workers` is a setting name that shouldn't be localized.
-
-
-
- {0} bütünleştirilmiş kodundan testler bulunamadı. Neden:{1}
-
-
-
-
-
- Yalnızca veri temelli test metotları parametrelere sahip olabilir. [DataRow] veya [DynamicData] kullanmak mı istediniz?
-
-
-
-
-
- '{0}' testinin yürütülmesi iptal edildi.
-
-
-
-
-
+
+
+
+
+
+
+ '{0}' testi yürütme zaman aşımı süresini aştı.
+
+
+
+
+ Testlerin sağlanan kaynakların herhangi birinde çalıştırılması seçili platformda desteklenmiyor
+
+
+
+
+ TestCleanup metodu ({0}.{1}) özel durum oluşturdu. {2}: {3}.
+
+
+
+
+ --- İç özel durum yığın izlemesinin sonu ---
+
+
+
+
+ UTA014: {0}: Bir bütünleştirilmiş kod içinde AssemblyCleanup özniteliği ile birden fazla metot tanımlanamaz.
+
+
+
+
+ UTA013: {0}: Bir bütünleştirilmiş kod içinde AssemblyInitialize özniteliği ile birden fazla metot tanımlanamaz.
+
+
+
+
+ UTA026: {0}: Bir sınıf içinde ClassCleanup özniteliği ile birden fazla metot tanımlanamaz.
+
+
+
+
+ UTA025: {0}: Bir sınıf içinde ClassInitialize özniteliği ile birden fazla metot tanımlanamaz.
+
+
+
+
+ UTA024: {0}: TestCleanup özniteliği ile birden fazla metot tanımlanamaz.
+
+
+
+
+ UTA018: {0}: TestInitialize özniteliği ile birden fazla metot tanımlanamaz.
+
+
+
+
+ Başlatma metodu {0}.{1} özel durum oluşturdu. {2}.
+
+
+
+
+ {0} sınıfının örneği oluşturulamıyor. Hata: {1}.
+
+
+
+
+ {0} sınıfı için TestContext özelliği ayarlanamıyor. Hata: {1}.
+
+
+
+
+ (Bir özel durum nedeniyle, {0} türündeki özel durum iletisi alınamadı.)
+
+
+
+
+ UTA031: {0} sınıfı geçerli bir TestContext özelliğine sahip değil. TestContext, TestContext türünde olmalı, statik olmamalı, genel olmalı ve salt okunur olmamalı. Örnek: public TestContext TestContext.
+
+
+
+
+ UTA001: TestClass özniteliği genel olmayan {0} sınıfında tanımlanmış
+
+
+
+
+ MSTestAdapter, '{1}' bütünleştirilmiş kodunun '{0}' sınıfındaki testleri bulamadı. Nedeni: {2}.
+
+
+
+
+ {0}: {1}
+
+
+
+
+ '{0}' test kaynağından türler yüklenemiyor. Kaynaktaki testlerin bazıları veya tümü bulunamayabilir.
+Hata: {1}
+
+
+
+
+ UTA015: Genel metot bir test metodu olamaz. {0}.{1} geçersiz imzaya sahip
+
+
+
+
+ Parametre null veya boş olmamalıdır.
+
+
+
+
+ Parametre sıfırdan büyük olmalıdır.
+
+
+
+
+ MSTestAdapter, '{1}' bütünleştirilmiş kodunun '{0}' sınıfında testleri bulamadı. Nedeni: {2}.
+
+
+
+
+ Dosya yok: {0}
+
+
+
+
+ UTA007: {0} sınıfında tanımlanan {1} metodunun imzası doğru değil. [TestMethod] özniteliğiyle işaretlenen test metodu statik olmamalı, genel olmalı, return-type değeri void olmalı ve hiçbir parametre almamalıdır. Örnek: public void Test.Class1.Test(). Bunlara ek olarak, test metodunda async-await kullanıyorsanız return-type değeri Task olmalıdır. Örnek: public async Task Test.Class1.Test2()
+
+
+
+
+ TestContext, Null olamaz.
+
+
+
+
+ Bütünleştirilmiş Kod Temizleme metodu ({0}.{1}) başarısız oldu. Hata İletisi: {2}. StackTrace: {3}
+
+
+
+
+ Bütünleştirilmiş Kod Başlatma metodu ({0}.{1}) özel durum oluşturdu. {2}: {3}. Test yürütmesi durduruluyor.
+
+
+
+
+ Sınıf Temizleme metodu ({0}.{1}) başarısız oldu. Hata İletisi: {2}. Yığın İzlemesi: {3}
+
+
+
+
+ Sınıf Başlatma metodu ({0}.{1}) özel durum oluşturdu. {2}: {3}.
+
+
+
+
+ Test yürütülürken özel durum oluşturuldu. TestMethodAttribute uzantısı kullanılıyorsa, lütfen satıcıya başvurun. Hata iletisi: {0}
+
+
+
+
+ Test yürütülürken hata oluştu. Uzantı tarafından hiç sonuç döndürülmedi. TestMethodAttribute uzantısı kullanılıyorsa, lütfen satıcıya başvurun.
+
+
+
+
+ {0}.{1} metodunun imzası yanlış. Metot statik, genel, değer döndürmeyen bir metot olmalı, hiçbir parametre almamalıdır. Bunlara ek olarak, metotta async-await kullanıyorsanız return-type değeri Task olmalıdır.
+
+
+
+
+ {0}.{1} metodunun imzası yanlış. Metot statik, genel, değer döndürmeyen bir metot olmalı ve TestContext türünde tek bir parametre almalıdır. Bunlara ek olarak, metotta async-await kullanıyorsanız return-type değeri Task olmalıdır.
+
+
+
+
+ UTA054: {0}.{1} geçersiz Timeout özniteliğine sahip. Zaman aşımı geçerli bir tamsayı değer olmalıdır ve 0'dan küçük olamaz.
+
+
+
+
+ UTA023: {0}: Önceden tanımlanmış {2} özelliği {1} metodunda tanımlanamaz.
+
+
+
+
+ UTA022: {0}.{1}: "{2}" özel özelliği zaten tanımlanmış. Değer olarak "{3}" kullanılıyor.
+
+
+
+
+ UTA021: {0}: {1} metodunda null veya boş özel özellik tanımlanmış. Özel özellik geçerli bir ada sahip olmalıdır.
+
+
+
+
+ {0}.{1} metodu yok.
+
+
+
+
+ {0} sınıfı için varsayılan oluşturucu alınamıyor.
+
+
+
+
+ {0}.TestContext özelliği bulunamıyor. Hata:{1}.
+
+
+
+
+ {0}.TestContext yanlış türe sahip.
+
+
+
+
+ {0}.{1} metodunun imzası yanlış. Metot statik olmayan, genel, değer döndürmeyen bir metot olmalı, hiçbir parametre almamalıdır. Bunlara ek olarak, metotta async-await kullanıyorsanız return-type değeri Task olmalıdır.
+
+
+
+
+ {0} türü alınamıyor. Hata: {1}.
+
+
+
+
+ {0} test metodu bulunamadı.
+
+
+
+
+ Hata Ayıklama İzleyici:
+
+
+
+
+ {0}.{1} metodu tarafından oluşturulan özel durum alınamadı.
+
+
+
+
+ {0}.{1} test metodu özel durum oluşturdu:
+{2}
+
+
+
+
+ {0} UWP projeleri için testte UI nesneleri kullanıyorsanız, testi UI iş parçacığında yürütmek için [TestMethod] yerine [UITestMethod] özniteliğini kullanabilirsiniz.
+
+
+
+
+ MSTestAdapterV2
+
+
+
+
+ Geçersiz '{0}' ayarları. Beklenmeyen XmlAttribute: '{1}'.
+
+
+
+
+ Geçersiz '{0}' ayarları. Beklenmeyen XmlElement: '{1}'.
+
+
+
+
+ {0} (Veri Satırı {1})
+
+
+
+
+ {0}.{1} test yöntemi üzerinde tanımlanan ExpectedException özniteliği, oluşturma sırasında bir özel durum oluşturdu.
+{2}
+
+
+
+
+ {0}.{1} test yöntemi, üzerinde tanımlanan ExpectedExceptionBaseAttribute öğesinden türetilmiş birden fazla öznitelik içeriyor. Bu türde yalnızca bir tane özniteliğe izin verilir.
+
+
+
+
+ Uyarı : MSTest V2 Adapter ile bir testsettings dosyası veya bir vsmdi dosyası desteklenmez.
+
+
+
+
+ TestContext İletileri:
+
+
+
+
+ {0} test sınıfı için Test Temizleme metodu çağrılırken hata oluştu: {1}
+
+
+
+
+ TestCleanup Yığın İzleme
+
+
+
+
+ [MSTest][Discovery][{0}] {1}
+
+
+
+
+ MSTest Yürütücü: {0} için Test Paralelleştirme etkin (Workers: {1}, Scope: {2}).
+
+
+
+
+ 'Scope' için geçersiz '{0}' değeri belirtildi. Desteklenen kapsamlar {1}.
+ 'Scope' is a setting name that shouldn't be localized.
+
+
+
+ 'Workers' için geçersiz '{0}' değeri belirtildi. Değer negatif olmayan bir tamsayı olmalıdır.
+ `Workers` is a setting name that shouldn't be localized.
+
+
+
+ {0} bütünleştirilmiş kodundan testler bulunamadı. Neden:{1}
+
+
+
+
+ Yalnızca veri temelli test metotları parametrelere sahip olabilir. [DataRow] veya [DynamicData] kullanmak mı istediniz?
+
+
+
+
+ '{0}' testinin yürütülmesi iptal edildi.
+
+
+
+
\ No newline at end of file
diff --git a/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.zh-Hans.xlf b/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.zh-Hans.xlf
index e44f789cd..bf78fc768 100644
--- a/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.zh-Hans.xlf
+++ b/src/Adapter/MSTest.CoreAdapter/Resources/xlf/Resource.zh-Hans.xlf
@@ -5,374 +5,313 @@
测试“{0}”的执行超时。
-
-
+
选定的平台不支持在任何提供的源中运行测试
-
-
+
TestCleanup 方法 {0}。{1} 引发异常。{2}: {3}。
-
-
+
---内部异常堆栈跟踪结束---
-
-
+
UTA014: {0}: 在一个程序集内部,不能定义多个具有 AssemblyCleanup 特性的方法。
-
-
+
UTA013: {0}: 在一个程序集内部,不能定义多个具有 AssemblyInitialize 特性的方法。
-
-
+
UTA026: {0}: 在一个类内部,不能定义多个具有 ClassCleanup 特性的方法。
-
-
+
UTA025: {0}: 在一个类内部,不能定义多个具有 ClassInitialize 特性的方法。
-
-
+
UTA024: {0}: 不能定义多个具有 TestCleanup 特性的方法。
-
-
+
UTA018: {0}: 不能定义多个具有 TestInitialize 特性的方法。
-
-
+
初始化方法 {0}.{1} 引发异常。{2}。
-
-
+
无法创建类 {0} 的实例。错误: {1}。
-
-
+
无法设置类 {0} 的 TestContext 属性。错误: {1}。
-
-
+
(因异常而未能获取类型为 {0} 的异常的消息。)
-
-
+
UTA031: 类 {0} 没有有效的 TestContext 属性。TestContext 的类型必须为 TestContext,必须是非静态的、公共的而且不能为只读。例如: public TestContext TestContext。
-
-
+
UTA001: 在非公共类 {0} 上定义的 TestClass 特性
-
-
+
由于 {2},MSTestAdapter 未能在程序集“{1}”的类“{0}”中发现测试。
-
-
+
{0}: {1}
-
-
+
无法从测试源“{0}”加载类型。可能无法发现此源中的部分或所有测试。
错误: {1}
-
-
+
UTA015: 泛型方法不可为测试方法。{0}.{1} 具有无效签名
-
-
+
参数不应为 NULL 或为空。
-
-
+
参数必须大于零。
-
-
+
MSTestAdapter 未能在程序集“{1}”的类“{0}”中发现测试。原因是 {2}。
-
-
+
文件不存在: {0}
-
-
+
UTA007: 在类 {0} 中定义的方法 {1} 没有正确的签名。用 [TestMethod] 特性标记的测试方法必须是返回类型为 void 的非静态的公共方法,并且不应采用任何参数。示例: public void Test.Class1.Test()。此外,如果你在测试方法中使用异步等待,则返回类型必须为 Task。示例: public async Task Test.Class1.Test2()
-
-
+
TestContext 不能为 NULL。
-
-
+
程序集清理方法 {0}.{1} 失败。错误消息: {2}。StackTrace: {3}
-
-
+
程序集初始化方法 {0}.{1} 引发异常。{2}: {3}。正在中止测试的执行。
-
-
+
类清理方法 {0}.{1} 失败。错误消息: {2}。堆栈跟踪: {3}
-
-
+
类初始化方法 {0}.{1} 引发异常。{2}: {3}。
-
-
+
执行测试时引发了异常。如果使用的是扩展 TestMethodAttribute,请与供应商联系。错误消息: {0}
-
-
+
执行测试时出错。扩展未返回任何结果。如果使用的是扩展 TestMethodAttribute ,请与供应商联系。
-
-
+
方法 {0}.{1} 具有错误的签名。该方法必须是静态的公共方法、不返回值并且不应采用任何参数。此外,如果在方法中使用同步等待,则返回类型必须为 Task。
-
-
+
方法 {0}.{1} 具有错误的签名。该方法必须是静态的公共方法、不返回值并且应采用一个 TestContext 类型的参数。此外,如果在方法中使用同步等待,则返回类型必须为 Task。
-
-
+
UTA054: {0}.{1} 具有无效的 Timeout 特性。超时值必须是有效的整数值而且不能小于 0。
-
-
+
UTA023: {0}: 不能在方法 {1} 上定义预定义属性 {2}。
-
-
+
UTA022: {0}.{1}: 已经定义了自定义属性“{2}”。其值为“{3}”。
-
-
+
UTA021: {0}: 对方法 {1} 定义了为 NULL 或为空的自定义属性。自定义属性必须具有有效名称。
-
-
+
方法 {0}.{1} 不存在。
-
-
+
无法获取类 {0} 的默认构造函数。
-
-
+
无法找到属性 {0}.TestContext。错误: {1}。
-
-
+
{0}.TestContext 的类型不正确。
-
-
+
方法 {0}.{1} 具有错误的签名。该方法必须是非静态的公共方法、不返回值并且不应采用任何参数。此外,如果在方法中使用同步等待,则返回类型必须为 Task。
-
-
+
无法获取类型 {0}。错误: {1}。
-
-
+
未找到测试方法 {0}。
-
-
+
调试跟踪:
-
-
+
未能获取测试方法 {0}.{1} 引发的异常。
-
-
+
测试方法 {0}.{1} 引发了异常:
{2}
-
-
+
{0} 对于 UWP 项目,如果在测试中使用 UI 对象,请考虑使用 [UITestMethod] 属性代替 [TestMethod] 属性在 UI 线程中执行测试。
-
-
+
MSTestAdapterV2
-
-
+
设置“{0}”无效。意外的 XmlAttribute:“{1}”。
-
-
+
设置“{0}”无效。意外的 XmlElement:“{1}”。
-
-
+
{0} (数据行 {1})
-
-
+
测试方法 {0}.{1} 上定义的 ExpectedException 属性在构造过程中引发了一个异常。
{2}
-
-
+
测试方法 {0}.{1} 具有多个在该方法上定义的 ExpectedExceptionBaseAttribute 的派生属性。仅允许一个此类属性。
-
-
+
警告: MSTest V2 适配器不支持 testsettings 文件或 vsmdi 文件。
-
-
+
TestContext 消息:
-
-
+
为测试类 {0} 调用 Test Cleanup 方法时出错: {1}
-
-
+
TestCleanup 堆栈跟踪
-
-
+
[MSTest][发现][{0}] {1}
-
-
+
MSTest 执行程序: 为 {0} 启用测试并行化(辅助角色: {1},范围: {2})。
-
-
+
@@ -387,20 +326,17 @@ Error: {1}
未能发现程序集 {0} 中的测试。原因: {1}
-
-
+
只有数据驱动的测试方法可具有参数。曾打算使用 [DataRow] 或 [DynamicData]?
-
-
+
已中止测试“{0}”的执行。
-
-
+