Skip to content

Commit

Permalink
Supporting core (#11326)
Browse files Browse the repository at this point in the history
* Supporting core

* changes for checks

* resolving some comments

* checks

* Adding L0 test

* Changing minor version

* adding more L0 tests

* adding bool
  • Loading branch information
20shivangi authored Sep 18, 2019
1 parent 2cf5aae commit f00f4c1
Show file tree
Hide file tree
Showing 24 changed files with 281 additions and 408 deletions.
184 changes: 96 additions & 88 deletions Tasks/AzurePowerShellV4/AzurePowerShell.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ $__vsts_input_errorActionPreference = Get-VstsInput -Name errorActionPreference
$__vsts_input_failOnStandardError = Get-VstsInput -Name FailOnStandardError
$targetAzurePs = Get-VstsInput -Name TargetAzurePs
$customTargetAzurePs = Get-VstsInput -Name CustomTargetAzurePs
$input_pwsh = Get-VstsInput -Name pwsh -AsBool
$input_workingDirectory = Get-VstsInput -Name workingDirectory -Require

# Validate the script path and args do not contains new-lines. Otherwise, it will
# break invoking the script via Invoke-Expression.
Expand All @@ -31,7 +33,7 @@ if ($targetAzurePs -eq $otherVersion) {
if ($customTargetAzurePs -eq $null) {
throw (Get-VstsLocString -Key InvalidAzurePsVersion $customTargetAzurePs)
} else {
$targetAzurePs = $customTargetAzurePs.Trim()
$targetAzurePs = $customTargetAzurePs.Trim()
}
}

Expand All @@ -48,109 +50,115 @@ if ($targetAzurePs -eq $latestVersion) {

$serviceName = Get-VstsInput -Name ConnectedServiceNameARM -Require
$endpoint = Get-VstsEndpoint -Name $serviceName -Require

$azureRMModulePath = "C:\Modules\azurerm_2.1.0"
$azureModulePath = "C:\Modules\azure_2.1.0"
$azPSModulePath = $env:PSModulePath

if ($azPSModulePath.split(";") -contains $azureRMModulePath) {
$azPSModulePath = (($azPSModulePath).Split(";") | ? { $_ -ne $azureRMModulePath }) -join ";"
write-verbose "$azureRMModulePath removed. Restart the prompt for the changes to take effect."
}
else {
write-verbose "$azureRMModulePath is not present in $azPSModulePath"
}

if ($azPSModulePath.split(";") -contains $azureModulePath) {
$azPSModulePath = (($azPSModulePath).Split(";") | ? { $_ -ne $azureModulePath }) -join ";"
write-verbose "$azureModulePath removed. Restart the prompt for the changes to take effect."
}
else {
write-verbose "$azureModulePath is not present in $azPSModulePath"
}

$env:PSModulePath = $azPSModulePath

CleanUp-PSModulePathForHostedAgent
Update-PSModulePathForHostedAgent -targetAzurePs $targetAzurePs

try
{
# Initialize Azure.
Import-Module $PSScriptRoot\ps_modules\VstsAzureHelpers_
Initialize-AzModule -Endpoint $endpoint -azVersion $targetAzurePs

# Trace the expression as it will be invoked.
$__vstsAzPSInlineScriptPath = $null
If ($scriptType -eq "InlineScript") {
$scriptArguments = $null
$__vstsAzPSInlineScriptPath = [System.IO.Path]::Combine($env:Agent_TempDirectory, ([guid]::NewGuid().ToString() + ".ps1"));
($scriptInline | Out-File $__vstsAzPSInlineScriptPath)
$scriptPath = $__vstsAzPSInlineScriptPath

# Generate the script contents.
Write-Host (Get-VstsLocString -Key 'GeneratingScript')
$UpdatePSModulePathArgument = $null;
if ($targetAzurePs)
{
$UpdatePSModulePathArgument = "-targetAzurePs $targetAzurePs"
}

$contents = @()
$contents += "`$ErrorActionPreference = '$__vsts_input_errorActionPreference'"
if ($env:system_debug -eq "true") {
$contents += "`$VerbosePreference = 'continue'"
}

$contents += ". $PSScriptRoot\UpdatePSModulePath.ps1 $UpdatePSModulePathArgument"
if ($scriptType -eq "InlineScript") {
$contents += "$scriptInline".Replace("`r`n", "`n").Replace("`n", "`r`n")
} else {
$contents += ". '$("$scriptPath".Replace("'", "''"))' $scriptArguments".Trim()
}

$scriptCommand = "& '$($scriptPath.Replace("'", "''"))' $scriptArguments"
Remove-Variable -Name scriptType
Remove-Variable -Name scriptPath
Remove-Variable -Name scriptInline
Remove-Variable -Name scriptArguments

# Remove all commands imported from VstsTaskSdk, other than Out-Default.
# Remove all commands imported from VstsAzureHelpers_.
Get-ChildItem -LiteralPath function: |
Where-Object {
($_.ModuleName -eq 'VstsTaskSdk' -and $_.Name -ne 'Out-Default') -or
($_.Name -eq 'Invoke-VstsTaskScript') -or
($_.ModuleName -eq 'VstsAzureHelpers_' )
} |
Remove-Item

# For compatibility with the legacy handler implementation, set the error action
# preference to continue. An implication of changing the preference to Continue,
# is that Invoke-VstsTaskScript will no longer handle setting the result to failed.
# Write the script to disk.
$__vstsAzPSScriptPath = [System.IO.Path]::Combine($env:Agent_TempDirectory, ([guid]::NewGuid().ToString() + ".ps1"));
$joinedContents = [System.String]::Join(
([System.Environment]::NewLine),
$contents)
$null = [System.IO.File]::WriteAllText(
$__vstsAzPSScriptPath,
$joinedContents,
([System.Text.Encoding]::UTF8))

# Prepare the external command values.
#
# Note, use "-Command" instead of "-File". On PowerShell v4 and V3 when using "-File", terminating
# errors do not cause a non-zero exit code.
if ($input_pwsh) {
$powershellPath = Get-Command -Name pwsh.exe -CommandType Application | Select-Object -First 1 -ExpandProperty Path
} else {
$powershellPath = Get-Command -Name powershell.exe -CommandType Application | Select-Object -First 1 -ExpandProperty Path
}
Assert-VstsPath -LiteralPath $powershellPath -PathType 'Leaf'
$arguments = "-NoLogo -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -Command `". '$($__vstsAzPSScriptPath.Replace("'", "''"))'`""
$splat = @{
'FileName' = $powershellPath
'Arguments' = $arguments
'WorkingDirectory' = $input_workingDirectory
}

# Switch to "Continue".
$global:ErrorActionPreference = 'Continue'
$failed = $false

# Undocumented VstsTaskSdk variable so Verbose/Debug isn't converted to ##vso[task.debug].
# Otherwise any content the ad-hoc script writes to the verbose pipeline gets dropped by
# the agent when System.Debug is not set.
$global:__vstsNoOverrideVerbose = $true

# Run the user's script. Redirect the error pipeline to the output pipeline to enable
# a couple goals due to compatibility with the legacy handler implementation:
# 1) STDERR from external commands needs to be converted into error records. Piping
# the redirected error output to an intermediate command before it is piped to
# Out-Default will implicitly perform the conversion.
# 2) The task result needs to be set to failed if an error record is encountered.
# As mentioned above, the requirement to handle this is an implication of changing
# the error action preference.
([scriptblock]::Create($scriptCommand)) |
ForEach-Object {
Remove-Variable -Name scriptCommand
Write-Host "##[command]$_"
. $_ 2>&1
} |
ForEach-Object {
if($_ -is [System.Management.Automation.ErrorRecord]) {
if($_.FullyQualifiedErrorId -eq "NativeCommandError" -or $_.FullyQualifiedErrorId -eq "NativeCommandErrorMessage") {
,$_
if($__vsts_input_failOnStandardError -eq $true) {
"##vso[task.complete result=Failed]"
}
}
else {
if($__vsts_input_errorActionPreference -eq "continue") {
,$_
if($__vsts_input_failOnStandardError -eq $true) {
"##vso[task.complete result=Failed]"
# Run the script.
Write-Host '========================== Starting Command Output ==========================='
if (!$__vsts_input_failOnStandardError) {
Invoke-VstsTool @splat
}
else {
$inError = $false
$errorLines = New-Object System.Text.StringBuilder
Invoke-VstsTool @splat 2>&1 |
ForEach-Object {
if ($_ -is [System.Management.Automation.ErrorRecord]) {
# Buffer the error lines.
$failed = $true
$inError = $true
$null = $errorLines.AppendLine("$($_.Exception.Message)")

# Write to verbose to mitigate if the process hangs.
Write-Verbose "STDERR: $($_.Exception.Message)"
} else {
# Flush the error buffer.
if ($inError) {
$inError = $false
$message = $errorLines.ToString().Trim()
$null = $errorLines.Clear()
if ($message) {
Write-VstsTaskError -Message $message
}
}
elseif($__vsts_input_errorActionPreference -eq "stop") {
throw $_
}

Write-Host "$_"
}
} else {
,$_
}

# Flush the error buffer one last time.
if ($inError) {
$inError = $false
$message = $errorLines.ToString().Trim()
$null = $errorLines.Clear()
if ($message) {
Write-VstsTaskError -Message $message
}
}
}

# Fail if any errors.
if ($failed) {
Write-VstsSetResult -Result 'Failed' -Message "Error detected" -DoNotThrow
}
}
finally {
if ($__vstsAzPSInlineScriptPath -and (Test-Path -LiteralPath $__vstsAzPSInlineScriptPath) ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"loc.instanceNameFormat": "Azure PowerShell script: $(ScriptType)",
"loc.releaseNotes": "Added support for Az Module and cross platform agents.",
"loc.group.displayName.AzurePowerShellVersionOptions": "Azure PowerShell version options",
"loc.group.displayName.advanced": "Advanced",
"loc.input.label.ConnectedServiceNameARM": "Azure Subscription",
"loc.input.help.ConnectedServiceNameARM": "Azure Resource Manager subscription to configure before running PowerShell",
"loc.input.label.ScriptType": "Script Type",
Expand All @@ -23,6 +24,10 @@
"loc.input.help.TargetAzurePs": "In case of hosted agents, the supported Azure PowerShell Version is: 1.0.0(Hosted VS2017 Queue).\nTo pick the latest version available on the agent, select \"Latest installed version\".\n\nFor private agents you can specify preferred version of Azure PowerShell using \"Specify version\"",
"loc.input.label.CustomTargetAzurePs": "Preferred Azure PowerShell Version",
"loc.input.help.CustomTargetAzurePs": "Preferred Azure PowerShell Version needs to be a proper semantic version eg. 1.2.3. Regex like 2.\\*,2.3.\\* is not supported. The Hosted VS2017 Pool currently supports Az module version: 1.0.0",
"loc.input.label.pwsh": "Use PowerShell Core",
"loc.input.help.pwsh": "If this is true, then on Windows the task will use pwsh.exe from your PATH instead of powershell.exe.",
"loc.input.label.workingDirectory": "Working Directory",
"loc.input.help.workingDirectory": "Working directory where the script is run.",
"loc.messages.GeneratingScript": "Generating script.",
"loc.messages.JS_FormattedCommand": "Formatted command: %s",
"loc.messages.InvalidScriptArguments0": "Invalid script arguments '{0}'. Line breaks are not allowed.",
Expand Down
27 changes: 27 additions & 0 deletions Tasks/AzurePowerShellV4/Tests/ChecksForPowerShell.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[CmdletBinding()]
param()

# Arrange.
. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1
$targetAzurePs = "4.1.0"
Register-Mock Get-VstsInput { "FilePath" } -- -Name ScriptType -Require
Register-Mock Get-VstsInput { "$PSScriptRoot/PerformsBasicFlow_TargetScript.ps1" } -- -Name ScriptPath
Register-Mock Get-VstsInput { $targetAzurePs } -- -Name TargetAzurePs
Register-Mock Get-VstsInput { 'arg1 arg2' } -- -Name ScriptArguments
Register-Mock Get-VstsInput { "continue" } -- -Name errorActionPreference
Register-Mock Get-VstsInput { $true } -- -Name FailOnStandardError
Register-Mock Get-VstsInput { $false } -- -Name pwsh -AsBool
Register-Mock Update-PSModulePathForHostedAgent
Register-Mock Get-Module
Register-Mock Initialize-AzModule
Register-Mock Get-VstsEndpoint { @{auth = @{ scheme = "ServicePrincipal" }} }
Register-Mock Remove-EndpointSecrets
Register-Mock Disconnect-AzureAndClearContext
Register-Mock Assert-VstsPath
Register-Mock Invoke-VstsTool { }

# Act.
$actual = & $PSScriptRoot\..\AzurePowerShell.ps1

Assert-WasCalled Invoke-VstsTool -Times 1
Assert-WasCalled Invoke-VstsTool -ArgumentsEvaluator {($args | ConvertTo-Json) -like '*powershell.exe*'}
27 changes: 27 additions & 0 deletions Tasks/AzurePowerShellV4/Tests/ChecksForPowerShellCore.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[CmdletBinding()]
param()

# Arrange.
. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1
$targetAzurePs = "4.1.0"
Register-Mock Get-VstsInput { "FilePath" } -- -Name ScriptType -Require
Register-Mock Get-VstsInput { "$PSScriptRoot/PerformsBasicFlow_TargetScript.ps1" } -- -Name ScriptPath
Register-Mock Get-VstsInput { $targetAzurePs } -- -Name TargetAzurePs
Register-Mock Get-VstsInput { 'arg1 arg2' } -- -Name ScriptArguments
Register-Mock Get-VstsInput { "continue" } -- -Name errorActionPreference
Register-Mock Get-VstsInput { $true } -- -Name FailOnStandardError
Register-Mock Get-VstsInput { $true } -- -Name pwsh -AsBool
Register-Mock Update-PSModulePathForHostedAgent
Register-Mock Get-Module
Register-Mock Initialize-AzModule
Register-Mock Get-VstsEndpoint { @{auth = @{ scheme = "ServicePrincipal" }} }
Register-Mock Remove-EndpointSecrets
Register-Mock Disconnect-AzureAndClearContext
Register-Mock Assert-VstsPath
Register-Mock Invoke-VstsTool { }

# Act.
$actual = & $PSScriptRoot\..\AzurePowerShell.ps1

Assert-WasCalled Invoke-VstsTool -Times 1
Assert-WasCalled Invoke-VstsTool -ArgumentsEvaluator {($args | ConvertTo-Json) -like '*pwsh.exe*'}
29 changes: 29 additions & 0 deletions Tasks/AzurePowerShellV4/Tests/ChecksForWorkingDirectory.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
[CmdletBinding()]
param()

# Arrange.
. $PSScriptRoot\..\..\..\Tests\lib\Initialize-Test.ps1
$targetAzurePs = "4.1.0"
$input_workingDirectory = "C:\Users"
Register-Mock Get-VstsInput { "FilePath" } -- -Name ScriptType -Require
Register-Mock Get-VstsInput { "$PSScriptRoot/PerformsBasicFlow_TargetScript.ps1" } -- -Name ScriptPath
Register-Mock Get-VstsInput { $targetAzurePs } -- -Name TargetAzurePs
Register-Mock Get-VstsInput { 'arg1 arg2' } -- -Name ScriptArguments
Register-Mock Get-VstsInput { "continue" } -- -Name errorActionPreference
Register-Mock Get-VstsInput { $true } -- -Name FailOnStandardError
Register-Mock Get-VstsInput { $true } -- -Name pwsh -AsBool
Register-Mock Get-VstsInput { $input_workingDirectory } -- -Name workingDirectory -Require
Register-Mock Update-PSModulePathForHostedAgent
Register-Mock Get-Module
Register-Mock Initialize-AzModule
Register-Mock Get-VstsEndpoint { @{auth = @{ scheme = "ServicePrincipal" }} }
Register-Mock Remove-EndpointSecrets
Register-Mock Disconnect-AzureAndClearContext
Register-Mock Assert-VstsPath
Register-Mock Invoke-VstsTool { }

# Act.
$actual = & $PSScriptRoot\..\AzurePowerShell.ps1

Assert-WasCalled Invoke-VstsTool -Times 1
Assert-WasCalled Invoke-VstsTool -ArgumentsEvaluator {($args | ConvertTo-Json) -like '*C:\\Users*'}
31 changes: 0 additions & 31 deletions Tasks/AzurePowerShellV4/Tests/DoesNotFailOnStandardError.ps1

This file was deleted.

This file was deleted.

Loading

0 comments on commit f00f4c1

Please sign in to comment.