From 54ee17025ae9c809e1c095286b5f64348833b760 Mon Sep 17 00:00:00 2001 From: paule96 Date: Mon, 15 Jun 2020 13:19:18 +0200 Subject: [PATCH 1/8] add warnings logic to powershell tasks --- Tasks/PowerShellV2/powershell.ps1 | 86 +++++++++++++++++++------------ Tasks/PowerShellV2/powershell.ts | 32 +++++++++--- Tasks/PowerShellV2/task.json | 8 +++ 3 files changed, 86 insertions(+), 40 deletions(-) diff --git a/Tasks/PowerShellV2/powershell.ps1 b/Tasks/PowerShellV2/powershell.ps1 index 3c15ebabbf21..3393eecf83bc 100644 --- a/Tasks/PowerShellV2/powershell.ps1 +++ b/Tasks/PowerShellV2/powershell.ps1 @@ -15,6 +15,7 @@ try { Write-Error (Get-VstsLocString -Key 'PS_InvalidErrorActionPreference' -ArgumentList $input_errorActionPreference) } } + $input_showWarnings = Get-VstsInput -Name 'showWarnings' -AsBool $input_failOnStderr = Get-VstsInput -Name 'failOnStderr' -AsBool $input_ignoreLASTEXITCODE = Get-VstsInput -Name 'ignoreLASTEXITCODE' -AsBool $input_pwsh = Get-VstsInput -Name 'pwsh' -AsBool @@ -25,7 +26,8 @@ try { $input_filePath = Get-VstsInput -Name 'filePath' -Require try { Assert-VstsPath -LiteralPath $input_filePath -PathType Leaf - } catch { + } + catch { Write-Error (Get-VstsLocString -Key 'PS_InvalidFilePath' -ArgumentList $input_filePath) } @@ -34,7 +36,8 @@ try { } $input_arguments = Get-VstsInput -Name 'arguments' - } else { + } + else { $input_script = Get-VstsInput -Name 'script' } @@ -48,7 +51,8 @@ try { if ("$input_targetType".ToUpperInvariant() -eq 'FILEPATH') { $contents += ". '$("$input_filePath".Replace("'", "''"))' $input_arguments".Trim() Write-Host (Get-VstsLocString -Key 'PS_FormattedCommand' -ArgumentList ($contents[-1])) - } else { + } + else { $contents += "$input_script".Replace("`r`n", "`n").Replace("`n", "`r`n") } @@ -61,14 +65,27 @@ try { $contents += '}' } + $joinedContents = [System.String]::Join( + ([System.Environment]::NewLine), + $contents); + if ($input_showWarnings) { + $joinedContents = ' + $warnings = New-Object System.Collections.ObjectModel.ObservableCollection[System.Management.Automation.WarningRecord]; + Register-ObjectEvent -InputObject $warnings -EventName CollectionChanged -Action { + if($Event.SourceEventArgs.Action -like "Add"){ + $Event.SourceEventArgs.NewItems | ForEach-Object { + Write-Host "##vso[task.logissue type=warning;]$_"; + } + } + }; + Invoke-Command {' + $joinedContents + '} -WarningVariable +warnings'; + } + # Write the script to disk. Assert-VstsAgent -Minimum '2.115.0' $tempDirectory = Get-VstsTaskVariable -Name 'agent.tempDirectory' -Require Assert-VstsPath -LiteralPath $tempDirectory -PathType 'Container' $filePath = [System.IO.Path]::Combine($tempDirectory, "$([System.Guid]::NewGuid()).ps1") - $joinedContents = [System.String]::Join( - ([System.Environment]::NewLine), - $contents) $null = [System.IO.File]::WriteAllText( $filePath, $joinedContents, @@ -80,14 +97,15 @@ try { # 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 { + } + 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 `". '$($filePath.Replace("'", "''"))'`"" $splat = @{ - 'FileName' = $powershellPath - 'Arguments' = $arguments + 'FileName' = $powershellPath + 'Arguments' = $arguments 'WorkingDirectory' = $input_workingDirectory } @@ -99,33 +117,35 @@ try { Write-Host '========================== Starting Command Output ===========================' if (!$input_failOnStderr) { Invoke-VstsTool @splat - } else { + } + 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 - } - } + ForEach-Object { + if ($_ -is [System.Management.Automation.ErrorRecord]) { + # Buffer the error lines. + $failed = $true + $inError = $true + $null = $errorLines.AppendLine("$($_.Exception.Message)") - Write-Host "$_" + # 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 + } } + + Write-Host "$_" } + } # Flush the error buffer one last time. if ($inError) { @@ -143,7 +163,8 @@ try { $failed = $true Write-Verbose "Unable to determine exit code" Write-VstsTaskError -Message (Get-VstsLocString -Key 'PS_UnableToDetermineExitCode') - } else { + } + else { if ($LASTEXITCODE -ne 0) { $failed = $true Write-VstsTaskError -Message (Get-VstsLocString -Key 'PS_ExitCode' -ArgumentList $LASTEXITCODE) @@ -154,6 +175,7 @@ try { if ($failed) { Write-VstsSetResult -Result 'Failed' -Message "Error detected" -DoNotThrow } -} finally { +} +finally { Trace-VstsLeavingInvocation $MyInvocation } diff --git a/Tasks/PowerShellV2/powershell.ts b/Tasks/PowerShellV2/powershell.ts index ad8dd97843f7..82eaee6b377d 100644 --- a/Tasks/PowerShellV2/powershell.ts +++ b/Tasks/PowerShellV2/powershell.ts @@ -19,6 +19,7 @@ async function run() { default: throw new Error(tl.loc('JS_InvalidErrorActionPreference', input_errorActionPreference)); } + let input_showWarnings = tl.getBoolInput('showWarnings', false); let input_failOnStderr = tl.getBoolInput('failOnStderr', false); let input_ignoreLASTEXITCODE = tl.getBoolInput('ignoreLASTEXITCODE', false); let input_workingDirectory = tl.getPathInput('workingDirectory', /*required*/ true, /*check*/ true); @@ -45,13 +46,28 @@ async function run() { console.log(tl.loc('GeneratingScript')); let contents: string[] = []; contents.push(`$ErrorActionPreference = '${input_errorActionPreference}'`); - if (input_targetType.toUpperCase() == 'FILEPATH') { - contents.push(`. '${input_filePath.replace(/'/g, "''")}' ${input_arguments}`.trim()); - console.log(tl.loc('JS_FormattedCommand', contents[contents.length - 1])); - } - else { - contents.push(input_script); + let script = ''; + if (input_targetType.toUpperCase() == 'FILEPATH') { + script = `. '${input_filePath.replace(/'/g, "''")}' ${input_arguments}`.trim(); + }else{ + script = `Invoke-Command {${input_script}}`; + } + if(input_showWarnings){ + script = ` + $warnings = New-Object System.Collections.ObjectModel.ObservableCollection[System.Management.Automation.WarningRecord]; + Register-ObjectEvent -InputObject $warnings -EventName CollectionChanged -Action { + if($Event.SourceEventArgs.Action -like "Add"){ + $Event.SourceEventArgs.NewItems | ForEach-Object { + Write-Host "##vso[task.logissue type=warning;]$_"; + } + } + }; + Invoke-Command {${script}} -WarningVariable +warnings; + `; } + contents.push(script); + // log with detail to avoid a warning output. + tl.logDetail(uuidV4(),tl.loc('JS_FormattedCommand', script),null, 'command', 'command', 0); if (!input_ignoreLASTEXITCODE) { contents.push(`if (!(Test-Path -LiteralPath variable:\LASTEXITCODE)) {`); @@ -113,10 +129,10 @@ async function run() { } }); } - + // Run bash. let exitCode: number = await powershell.exec(options); - + // Fail on exit code. if (exitCode !== 0) { tl.setResult(tl.TaskResult.Failed, tl.loc('JS_ExitCode', exitCode)); diff --git a/Tasks/PowerShellV2/task.json b/Tasks/PowerShellV2/task.json index 15251508df26..82d52b195bb6 100644 --- a/Tasks/PowerShellV2/task.json +++ b/Tasks/PowerShellV2/task.json @@ -97,6 +97,14 @@ "helpMarkDown": "If this is true, this task will fail if any errors are written to the error pipeline, or if any data is written to the Standard Error stream. Otherwise the task will rely on the exit code to determine failure.", "groupName": "advanced" }, + { + "name": "showWarnings", + "type": "boolean", + "label": "Show warnings as azure devops warnings", + "required": true, + "helpMarkDown": "If this is true, and your script writes a warning you pipline is success but with warnings.", + "groupName": "advanced" + }, { "name": "ignoreLASTEXITCODE", "type": "boolean", From a41c00e800984ba1f5417b5048f0f54400c82c07 Mon Sep 17 00:00:00 2001 From: paule96 Date: Mon, 15 Jun 2020 13:23:10 +0200 Subject: [PATCH 2/8] bump version --- Tasks/PowerShellV2/task.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tasks/PowerShellV2/task.json b/Tasks/PowerShellV2/task.json index 82d52b195bb6..28e29e93468b 100644 --- a/Tasks/PowerShellV2/task.json +++ b/Tasks/PowerShellV2/task.json @@ -17,8 +17,8 @@ "author": "Microsoft Corporation", "version": { "Major": 2, - "Minor": 170, - "Patch": 1 + "Minor": 172, + "Patch": 0 }, "releaseNotes": "Script task consistency. Added support for macOS and Linux.", "minimumAgentVersion": "2.115.0", From 3b09e1242bc42f2a8fe8e865ebaf51ce0e4891f4 Mon Sep 17 00:00:00 2001 From: paule96 Date: Mon, 15 Jun 2020 13:39:31 +0200 Subject: [PATCH 3/8] fix tests --- Tasks/PowerShellV2/powershell.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tasks/PowerShellV2/powershell.ts b/Tasks/PowerShellV2/powershell.ts index 82eaee6b377d..ee4dd2083a8a 100644 --- a/Tasks/PowerShellV2/powershell.ts +++ b/Tasks/PowerShellV2/powershell.ts @@ -50,7 +50,7 @@ async function run() { if (input_targetType.toUpperCase() == 'FILEPATH') { script = `. '${input_filePath.replace(/'/g, "''")}' ${input_arguments}`.trim(); }else{ - script = `Invoke-Command {${input_script}}`; + script = `${input_script}`; } if(input_showWarnings){ script = ` From 3b861f1603b3554e57bdcbcbed9bd85830513baa Mon Sep 17 00:00:00 2001 From: paule96 Date: Wed, 5 Aug 2020 10:04:24 +0200 Subject: [PATCH 4/8] fix spelling in task.json --- Tasks/PowerShellV2/task.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tasks/PowerShellV2/task.json b/Tasks/PowerShellV2/task.json index 28e29e93468b..947f9bcad849 100644 --- a/Tasks/PowerShellV2/task.json +++ b/Tasks/PowerShellV2/task.json @@ -102,7 +102,7 @@ "type": "boolean", "label": "Show warnings as azure devops warnings", "required": true, - "helpMarkDown": "If this is true, and your script writes a warning you pipline is success but with warnings.", + "helpMarkDown": "If this is true, and your script writes a warning you pipeline is success but with warnings.", "groupName": "advanced" }, { From 8185be248b3bbd6c10e903d944ee12d03b2383b5 Mon Sep 17 00:00:00 2001 From: paule96 Date: Fri, 9 Oct 2020 10:52:18 +0200 Subject: [PATCH 5/8] add PR feedback --- Tasks/PowerShellV2/powershell.ts | 15 +++++++-------- Tasks/PowerShellV2/task.json | 9 +++++---- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Tasks/PowerShellV2/powershell.ts b/Tasks/PowerShellV2/powershell.ts index ee4dd2083a8a..e4b85ef5dcf3 100644 --- a/Tasks/PowerShellV2/powershell.ts +++ b/Tasks/PowerShellV2/powershell.ts @@ -35,7 +35,7 @@ async function run() { input_arguments = tl.getInput('arguments') || ''; } - else if(input_targetType.toUpperCase() == 'INLINE') { + else if (input_targetType.toUpperCase() == 'INLINE') { input_script = tl.getInput('script', false) || ''; } else { @@ -47,12 +47,12 @@ async function run() { let contents: string[] = []; contents.push(`$ErrorActionPreference = '${input_errorActionPreference}'`); let script = ''; - if (input_targetType.toUpperCase() == 'FILEPATH') { + if (input_targetType.toUpperCase() == 'FILEPATH') { script = `. '${input_filePath.replace(/'/g, "''")}' ${input_arguments}`.trim(); - }else{ + } else { script = `${input_script}`; - } - if(input_showWarnings){ + } + if (input_showWarnings) { script = ` $warnings = New-Object System.Collections.ObjectModel.ObservableCollection[System.Management.Automation.WarningRecord]; Register-ObjectEvent -InputObject $warnings -EventName CollectionChanged -Action { @@ -67,7 +67,7 @@ async function run() { } contents.push(script); // log with detail to avoid a warning output. - tl.logDetail(uuidV4(),tl.loc('JS_FormattedCommand', script),null, 'command', 'command', 0); + tl.logDetail(uuidV4(), tl.loc('JS_FormattedCommand', script), null, 'command', 'command', 0); if (!input_ignoreLASTEXITCODE) { contents.push(`if (!(Test-Path -LiteralPath variable:\LASTEXITCODE)) {`); @@ -129,10 +129,9 @@ async function run() { } }); } - + // Run bash. let exitCode: number = await powershell.exec(options); - // Fail on exit code. if (exitCode !== 0) { tl.setResult(tl.TaskResult.Failed, tl.loc('JS_ExitCode', exitCode)); diff --git a/Tasks/PowerShellV2/task.json b/Tasks/PowerShellV2/task.json index 28e29e93468b..92e36ba8e09c 100644 --- a/Tasks/PowerShellV2/task.json +++ b/Tasks/PowerShellV2/task.json @@ -1,7 +1,7 @@ { - "id": "E213FF0F-5D5C-4791-802D-52EA3E7BE1F1", + "id": "78d85642-bc1d-44e4-a10b-ac0e8589ad21", "name": "PowerShell", - "friendlyName": "PowerShell", + "friendlyName": "(paje) PowerShell", "description": "Run a PowerShell script on Linux, macOS, or Windows", "helpUrl": "https://docs.microsoft.com/azure/devops/pipelines/tasks/utility/powershell", "helpMarkDown": "[Learn more about this task](https://go.microsoft.com/fwlink/?LinkID=613736)", @@ -17,7 +17,7 @@ "author": "Microsoft Corporation", "version": { "Major": 2, - "Minor": 172, + "Minor": 177, "Patch": 0 }, "releaseNotes": "Script task consistency. Added support for macOS and Linux.", @@ -101,7 +101,8 @@ "name": "showWarnings", "type": "boolean", "label": "Show warnings as azure devops warnings", - "required": true, + "required": false, + "defaultValue": "false", "helpMarkDown": "If this is true, and your script writes a warning you pipline is success but with warnings.", "groupName": "advanced" }, From df88900daf0beb5da84d4431251e7fc9db9fc5bc Mon Sep 17 00:00:00 2001 From: paule96 Date: Fri, 9 Oct 2020 10:56:58 +0200 Subject: [PATCH 6/8] =?UTF-8?q?remove=20own=20informations=20=F0=9F=A4=B7?= =?UTF-8?q?=E2=80=8D=E2=99=80=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Tasks/PowerShellV2/task.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tasks/PowerShellV2/task.json b/Tasks/PowerShellV2/task.json index ba84132404a4..0b0e8a3c7d32 100644 --- a/Tasks/PowerShellV2/task.json +++ b/Tasks/PowerShellV2/task.json @@ -1,7 +1,7 @@ { - "id": "78d85642-bc1d-44e4-a10b-ac0e8589ad21", + "id": "E213FF0F-5D5C-4791-802D-52EA3E7BE1F1", "name": "PowerShell", - "friendlyName": "(paje) PowerShell", + "friendlyName": "PowerShell", "description": "Run a PowerShell script on Linux, macOS, or Windows", "helpUrl": "https://docs.microsoft.com/azure/devops/pipelines/tasks/utility/powershell", "helpMarkDown": "[Learn more about this task](https://go.microsoft.com/fwlink/?LinkID=613736)", From 180dfc46ece6daf959bb19923702b2b306484ef3 Mon Sep 17 00:00:00 2001 From: paule96 Date: Fri, 16 Oct 2020 20:14:42 +0200 Subject: [PATCH 7/8] Update Tasks/PowerShellV2/task.json Co-authored-by: Anatoly Bolshakov --- Tasks/PowerShellV2/task.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tasks/PowerShellV2/task.json b/Tasks/PowerShellV2/task.json index 0b0e8a3c7d32..b92078091f1f 100644 --- a/Tasks/PowerShellV2/task.json +++ b/Tasks/PowerShellV2/task.json @@ -103,7 +103,7 @@ "label": "Show warnings as azure devops warnings", "required": false, "defaultValue": "false", - "helpMarkDown": "If this is true, and your script writes a warning you pipeline is success but with warnings.", + "helpMarkDown": "If this is true, and your script writes a warnings - they are shown as warnings also in pipeline logs", "groupName": "advanced" }, { @@ -160,4 +160,4 @@ "PS_InvalidFilePath": "Invalid file path '{0}'. A path to a .ps1 file is required.", "PS_UnableToDetermineExitCode": "Unexpected exception. Unable to determine the exit code from powershell." } -} \ No newline at end of file +} From 2094e8a7f2071c40676f5119c431899d4a31b93b Mon Sep 17 00:00:00 2001 From: paule96 Date: Fri, 16 Oct 2020 20:17:34 +0200 Subject: [PATCH 8/8] fix pr comments - fix version number in task.loc - fix casing of Azure DevOps in task.json --- Tasks/PowerShellV2/task.json | 2 +- Tasks/PowerShellV2/task.loc.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Tasks/PowerShellV2/task.json b/Tasks/PowerShellV2/task.json index b92078091f1f..2084c00d1718 100644 --- a/Tasks/PowerShellV2/task.json +++ b/Tasks/PowerShellV2/task.json @@ -100,7 +100,7 @@ { "name": "showWarnings", "type": "boolean", - "label": "Show warnings as azure devops warnings", + "label": "Show warnings as Azure DevOps warnings", "required": false, "defaultValue": "false", "helpMarkDown": "If this is true, and your script writes a warnings - they are shown as warnings also in pipeline logs", diff --git a/Tasks/PowerShellV2/task.loc.json b/Tasks/PowerShellV2/task.loc.json index 7a4f1c8481a5..896b461791e5 100644 --- a/Tasks/PowerShellV2/task.loc.json +++ b/Tasks/PowerShellV2/task.loc.json @@ -17,8 +17,8 @@ "author": "Microsoft Corporation", "version": { "Major": 2, - "Minor": 170, - "Patch": 1 + "Minor": 177, + "Patch": 0 }, "releaseNotes": "ms-resource:loc.releaseNotes", "minimumAgentVersion": "2.115.0",