Skip to content

Commit

Permalink
[MSBuildHelpers] Prepared for migration to NPM (#13962)
Browse files Browse the repository at this point in the history
Prepared MSBuildHelpers package for publishing to NPM
  • Loading branch information
Maxim Zaytsev authored Dec 1, 2020
1 parent f4f3e5a commit ba99437
Show file tree
Hide file tree
Showing 63 changed files with 1,934 additions and 0 deletions.
47 changes: 47 additions & 0 deletions common-npm-packages/MSBuildHelpers/ArgumentFunctions.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
function Format-MSBuildArguments {
[CmdletBinding()]
param(
[string]$MSBuildArguments,
[string]$Platform,
[string]$Configuration,
[string]$VSVersion,
[switch]$MaximumCpuCount)

Trace-VstsEnteringInvocation $MyInvocation
try {
if ($Platform) {
Test-MSBuildParam $Platform 'Platform'
$MSBuildArguments = "$MSBuildArguments /p:platform=`"$Platform`""
}

if ($Configuration) {
Test-MSBuildParam $Configuration 'Configuration'
$MSBuildArguments = "$MSBuildArguments /p:configuration=`"$Configuration`""
}

if ($VSVersion) {
$MSBuildArguments = "$MSBuildArguments /p:VisualStudioVersion=`"$VSVersion`""
}

if ($MaximumCpuCount) {
$MSBuildArguments = "$MSBuildArguments /m"
}

$userAgent = Get-VstsTaskVariable -Name AZURE_HTTP_USER_AGENT
if ($userAgent) {
$MSBuildArguments = "$MSBuildArguments /p:_MSDeployUserAgent=`"$userAgent`""
}

$MSBuildArguments
} finally {
Trace-VstsLeavingInvocation $MyInvocation
}
}

function Test-MSBuildParam ([string]$msbuildParam, [string]$parameterName)
{
if ($msBuildParam -match '[<>*|:\/&%"#?]')
{
throw "The value of MSBuild parameter '$parameterName' ($msBuildParam) contains an invalid character. The value of $parameterName may not contain any of the following characters: < > * | : \ / & % `" # ?"
}
}
176 changes: 176 additions & 0 deletions common-npm-packages/MSBuildHelpers/InvokeFunctions.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
########################################
# Public functions.
########################################
function Invoke-BuildTools {
[CmdletBinding()]
param(
[switch]$NuGetRestore,
[string[]]$SolutionFiles,
[string]$MSBuildLocation, # TODO: Switch MSBuildLocation to mandatory. Both callers (MSBuild and VSBuild task) throw prior to reaching here if MSBuild cannot be resolved.
[string]$MSBuildArguments,
[switch]$Clean,
[switch]$NoTimelineLogger,
[switch]$CreateLogFile,
[string]$LogFileVerbosity)

Trace-VstsEnteringInvocation $MyInvocation
try {
foreach ($file in $SolutionFiles) {
if ($NuGetRestore) {
Invoke-NuGetRestore -File $file
}

$splat = @{ }

if ($LogFileVerbosity) {
$splat["LogFileVerbosity"] = $LogFileVerbosity
}

if ($Clean) {
if ($CreateLogFile) {
$splat["LogFile"] = "$file-clean.log"
}
Invoke-MSBuild -ProjectFile $file -Targets Clean -MSBuildPath $MSBuildLocation -AdditionalArguments $MSBuildArguments -NoTimelineLogger:$NoTimelineLogger @splat
}

# If we cleaned and passed /t targets, we don't need to run them again
if (!$Clean -or $MSBuildArguments -notmatch "[/-]t(arget)?:\S+") {
if ($CreateLogFile) {
$splat["LogFile"] = "$file.log"
}
Invoke-MSBuild -ProjectFile $file -MSBuildPath $MSBuildLocation -AdditionalArguments $MSBuildArguments -NoTimelineLogger:$NoTimelineLogger @splat
}
}
} finally {
Trace-VstsLeavingInvocation $MyInvocation
}
}

########################################
# Private functions.
########################################
function Invoke-MSBuild {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true, Position = 1)]
[string]$ProjectFile,
[string]$Targets,
[string]$LogFile,
[string]$LogFileVerbosity,
[switch]$NoTimelineLogger,
[string]$MSBuildPath, # TODO: Switch MSBuildPath to mandatory. Both callers (MSBuild and VSBuild task) throw prior to reaching here if MSBuild cannot be resolved.
[string]$AdditionalArguments)

Trace-VstsEnteringInvocation $MyInvocation
try {
# Get the MSBuild path.
if (!$MSBuildPath) {
$MSBuildPath = Get-MSBuildPath # TODO: Delete this condition block. Both callers (MSBuild and VSBuild task) throw prior to reaching here if MSBuild cannot be resolved.
} else {
$MSBuildPath = [System.Environment]::ExpandEnvironmentVariables($MSBuildPath)
if ($MSBuildPath -notlike '*msbuild.exe') {
$MSBuildPath = [System.IO.Path]::Combine($MSBuildPath, 'msbuild.exe')
}
}

# Validate the path exists.
$null = Assert-VstsPath -LiteralPath $MSBuildPath -PathType Leaf

# Don't show the logo and do not allow node reuse so all child nodes are shut down once the master
# node has completed build orchestration.
$arguments = "`"$ProjectFile`" /nologo /nr:false"

# Add the targets if specified.
if ($Targets) {
$arguments = "$arguments /t:`"$Targets`""
}

# If a log file was specified then hook up the default file logger.
if ($LogFile) {
$arguments = "$arguments /fl /flp:`"logfile=$LogFile;verbosity=$LogFileVerbosity`""
}

# Start the detail timeline.
$detailId = ''
if (!$NoTimelineLogger) {
$detailId = [guid]::NewGuid()
$detailName = Get-VstsLocString -Key MSB_Build0 -ArgumentList ([System.IO.Path]::GetFileName($ProjectFile))
$detailStartTime = [datetime]::UtcNow.ToString('O')
Write-VstsLogDetail -Id $detailId -Type Process -Name $detailName -Progress 0 -StartTime $detailStartTime -State Initialized -AsOutput
}

# Store the solution folder so we can provide solution-relative paths (for now) for the project events.
$solutionDirectory = [System.IO.Path]::GetDirectoryName($ProjectFile)

# Hook up the custom logger.
$loggerAssembly = "$PSScriptRoot\msbuildlogger\Microsoft.TeamFoundation.DistributedTask.MSBuild.Logger.dll"
Assert-VstsPath -LiteralPath $loggerAssembly -PathType Leaf
$arguments = "$arguments /dl:CentralLogger,`"$loggerAssembly`";`"RootDetailId=$($detailId)|SolutionDir=$($solutionDirectory)`"*ForwardingLogger,`"$loggerAssembly`""

# Append additional arguments.
if ($AdditionalArguments) {
$arguments = "$arguments $AdditionalArguments"
}

$global:LASTEXITCODE = ''
try {
# Invoke MSBuild.
Invoke-VstsTool -FileName $MSBuildPath -Arguments $arguments -RequireExitCodeZero
if ($LASTEXITCODE -ne 0) {
Write-VstsSetResult -Result Failed -DoNotThrow
}
} finally {
# Complete the detail timeline.
if (!$NoTimelineLogger) {
if ($LASTEXITCODE -ne 0) {
$detailResult = 'Failed'
} else {
$detailResult = 'Succeeded'
}

$detailFinishTime = [datetime]::UtcNow.ToString('O')
Write-VstsLogDetail -Id $detailId -FinishTime $detailFinishTime -Progress 100 -State Completed -Result $detailResult -AsOutput
}

if ($LogFile) {
if (Test-Path -Path $LogFile) {
Write-Host "##vso[task.uploadfile]$LogFile"
} else {
Write-Verbose "Skipping upload of '$LogFile' since it does not exist."
}
}
}
} finally {
Trace-VstsLeavingInvocation $MyInvocation
}
}

function Invoke-NuGetRestore {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true, Position = 1)]
[string]$File)

Trace-VstsEnteringInvocation $MyInvocation
try {
Write-Warning (Get-VstsLocString -Key MSB_RestoreNuGetPackagesDeprecated)
try {
$nuGetPath = Assert-VstsPath -LiteralPath "$(Get-VstsTaskVariable -Name Agent.HomeDirectory -Require)\externals\nuget\NuGet.exe" -PathType Leaf -PassThru
} catch {
# Temporary fallback logic for legacy Windows agent.
$nuGetPath = Assert-VstsPath -LiteralPath "$(Get-VstsTaskVariable -Name Agent.HomeDirectory -Require)\Agent\Worker\Tools\NuGet.exe" -PathType Leaf -PassThru
}

if ($env:NUGET_EXTENSIONS_PATH) {
Write-Host (Get-VstsLocString -Key MSB_DetectedNuGetExtensionsLoaderPath0 -ArgumentList $env:NUGET_EXTENSIONS_PATH)
}

$directory = [System.IO.Path]::GetDirectoryName($file)
Invoke-VstsTool -FileName $nuGetPath -Arguments "restore `"$file`" -NonInteractive" -WorkingDirectory $directory -RequireExitCodeZero
if ($LASTEXITCODE -ne 0) {
Write-VstsSetResult -Result Failed -DoNotThrow
}
} finally {
Trace-VstsLeavingInvocation $MyInvocation
}
}
17 changes: 17 additions & 0 deletions common-npm-packages/MSBuildHelpers/MSBuildHelpers.psm1
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[CmdletBinding()]
param()
Import-VstsLocStrings "$PSScriptRoot\module.json"
. $PSScriptRoot\ArgumentFunctions
. $PSScriptRoot\InvokeFunctions
. $PSScriptRoot\PathFunctions
Export-ModuleMember -Function @(
# Argument functions.
'Format-MSBuildArguments'
# Invoke functions.
'Invoke-BuildTools'
# Path functions.
'Get-MSBuildPath'
'Get-SolutionFiles'
'Get-VisualStudio'
'Select-MSBuildPath'
)
Loading

0 comments on commit ba99437

Please sign in to comment.