From 718a306d2c1dcafc85f0717887b1547ef37dedd8 Mon Sep 17 00:00:00 2001 From: Konstantin Tyukalov <52399739+KonstantinTyukalov@users.noreply.github.com> Date: Tue, 30 Jan 2024 15:49:05 +0400 Subject: [PATCH] Added feature helpers (#1010) * Add node tl feature helper * Fix typescript err * Update changelog * Bump package version * node: Format debug message * powershell: Add Get-PipelineFeature * powershell: Bump version to 0.19.0 * Reset InputFunctions encoding --- node/CHANGELOG.md | 8 +++++ node/mock-task.ts | 1 + node/package-lock.json | 2 +- node/package.json | 2 +- node/task.ts | 27 ++++++++++++-- node/test/inputtests.ts | 34 ++++++++++++++++++ .../L0/Get-PipelineFeature.InputsTest.ps1 | 36 +++++++++++++++++++ powershell/VstsTaskSdk/InputFunctions.ps1 | 31 ++++++++++++++++ powershell/VstsTaskSdk/VstsTaskSdk.psm1 | 1 + powershell/package-lock.json | 2 +- powershell/package.json | 2 +- 11 files changed, 140 insertions(+), 6 deletions(-) create mode 100644 powershell/Tests/L0/Get-PipelineFeature.InputsTest.ps1 diff --git a/node/CHANGELOG.md b/node/CHANGELOG.md index 6ba129630..ee5b4713f 100644 --- a/node/CHANGELOG.md +++ b/node/CHANGELOG.md @@ -2,6 +2,14 @@ ## 4.x +### 4.9.0 + +- Added internal feature helpers [#1010](https://github.com/microsoft/azure-pipelines-task-lib/pull/1010) + +### 4.8.0 + +- Added `source` property for error/warning [#1009](https://github.com/microsoft/azure-pipelines-task-lib/pull/1009) + ### 4.7.0 Replaced mockery - [#989](https://github.com/microsoft/azure-pipelines-task-lib/pull/989) diff --git a/node/mock-task.ts b/node/mock-task.ts index 02a66b867..28c4af1cb 100644 --- a/node/mock-task.ts +++ b/node/mock-task.ts @@ -62,6 +62,7 @@ module.exports.getInput = task.getInput; module.exports.getInputRequired = task.getInputRequired; module.exports.getBoolInput = task.getBoolInput; module.exports.getBoolFeatureFlag = task.getBoolFeatureFlag; +module.exports.getPipelineFeature = task.getPipelineFeature; module.exports.getDelimitedInput = task.getDelimitedInput; module.exports.filePathSupplied = task.filePathSupplied; diff --git a/node/package-lock.json b/node/package-lock.json index 372e1f2a1..bff473589 100644 --- a/node/package-lock.json +++ b/node/package-lock.json @@ -1,6 +1,6 @@ { "name": "azure-pipelines-task-lib", - "version": "4.8.2", + "version": "4.9.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/node/package.json b/node/package.json index 761d76895..8a89b7e58 100644 --- a/node/package.json +++ b/node/package.json @@ -1,6 +1,6 @@ { "name": "azure-pipelines-task-lib", - "version": "4.8.2", + "version": "4.9.0", "description": "Azure Pipelines Task SDK", "main": "./task.js", "typings": "./task.d.ts", diff --git a/node/task.ts b/node/task.ts index a8af68d50..ae41a78fd 100644 --- a/node/task.ts +++ b/node/task.ts @@ -279,10 +279,11 @@ export function getBoolInput(name: string, required?: boolean): boolean { /** * Gets the value of an feature flag and converts to a bool. - * + * @IMPORTANT This method is only for internal Microsoft development. Do not use it for external tasks. * @param name name of the feature flag to get. * @param defaultValue default value of the feature flag in case it's not found in env. (optional. Default value = false) * @returns boolean + * @deprecated Don't use this for new development. Use getPipelineFeature instead. */ export function getBoolFeatureFlag(ffName: string, defaultValue: boolean = false): boolean { const ffValue = process.env[ffName]; @@ -297,6 +298,28 @@ export function getBoolFeatureFlag(ffName: string, defaultValue: boolean = false return ffValue.toLowerCase() === "true"; } +/** + * Gets the value of an task feature and converts to a bool. + * @IMPORTANT This method is only for internal Microsoft development. Do not use it for external tasks. + * @param name name of the feature to get. + * @returns boolean + */ +export function getPipelineFeature(featureName: string): boolean { + const variableName = im._getVariableKey(`DistributedTask.Tasks.${featureName}`); + const featureValue = process.env[variableName]; + + if (!featureValue) { + debug(`Feature '${featureName}' not found. Returning false as default.`); + return false; + } + + const boolValue = featureValue.toLowerCase() === "true"; + + debug(`Feature '${featureName}' = '${featureValue}'. Processed as '${boolValue}'.`); + + return boolValue; +} + /** * Gets the value of an input and splits the value using a delimiter (space, comma, etc). * Empty values are removed. This function is useful for splitting an input containing a simple @@ -801,7 +824,7 @@ export function mkdirP(p: string): void { let testDir: string = p; while (true) { // validate the loop is not out of control - if (stack.length >= (process.env['TASKLIB_TEST_MKDIRP_FAILSAFE'] || 1000)) { + if (stack.length >= Number(process.env['TASKLIB_TEST_MKDIRP_FAILSAFE'] || 1000)) { // let the framework throw debug('loop is out of control'); fs.mkdirSync(p); diff --git a/node/test/inputtests.ts b/node/test/inputtests.ts index 51109f555..ce1061290 100644 --- a/node/test/inputtests.ts +++ b/node/test/inputtests.ts @@ -1200,4 +1200,38 @@ describe('Input Tests', function () { assert.equal(ffValue, true); }) }); + + describe('Pipeline features tests', () => { + it(`Should return if no feature variable present.`, () => { + const featureName = "TestFeature" + delete process.env[im._getVariableKey(`DistributedTask.Tasks.${featureName}`)]; + + const ffValue = tl.getPipelineFeature(featureName); + + assert.deepStrictEqual(ffValue, false); + }) + + const testInputs = ([ + ["true", true], + ["TRUE", true], + ["TruE", true], + ["false", false], + ["treu", false], + ["fasle", false], + ["On", false], + ["", false], + [undefined, false] + ] as [string, boolean][]) + for (const [input, expected] of testInputs) { + it(`Should return '${expected}' if feature is '${input}'`, () => { + const featureVariable = "DISTRIBUTEDTASK_TASKS_TESTFEATURE"; + const featureName = "TestFeature"; + process.env[featureVariable] = input; + + const result = tl.getPipelineFeature(featureName); + + assert.deepStrictEqual(result, expected); + }) + } + }) }); diff --git a/powershell/Tests/L0/Get-PipelineFeature.InputsTest.ps1 b/powershell/Tests/L0/Get-PipelineFeature.InputsTest.ps1 new file mode 100644 index 000000000..e0bb80251 --- /dev/null +++ b/powershell/Tests/L0/Get-PipelineFeature.InputsTest.ps1 @@ -0,0 +1,36 @@ +[CmdletBinding()] +param() + +. $PSScriptRoot\..\lib\Initialize-Test.ps1 + +$featureName = "TestFeature" +$featureVariable = "DISTRIBUTEDTASK_TASKS_TESTFEATURE" + +Invoke-VstsTaskScript -ScriptBlock { + $testInputs = @( + @("true", $true), + @("TRUE", $true), + @("TruE", $true), + @("false", $false), + @("treu", $false), + @("fasle", $false), + @("On", $false), + @("", $false), + @($null, $false) + ) + foreach ($testInput in $testInputs) { + $inputValue = $testInput[0] + $expectedValue = $testInput[1] + + Set-Item -Path env:$featureVariable -Value $inputValue + + $result = Get-VstsPipelineFeature -FeatureName $featureName + + try { + Assert-AreEqual -Expected $expectedValue -Actual $result -Message "Suite failed. Input value: '$inputValue'" + } + finally { + ${env:$featureVariable} = "" + } + } +} diff --git a/powershell/VstsTaskSdk/InputFunctions.ps1 b/powershell/VstsTaskSdk/InputFunctions.ps1 index d7eb7c282..071d5cacb 100644 --- a/powershell/VstsTaskSdk/InputFunctions.ps1 +++ b/powershell/VstsTaskSdk/InputFunctions.ps1 @@ -320,6 +320,37 @@ function Set-TaskVariable { Write-SetVariable -Name $Name -Value $Value -Secret:$Secret } +<# +.SYNOPSIS +Gets the value of an task feature and converts to a bool. + +.PARAMETER $FeatureName +Name of the feature to get. + +.NOTES +This method is only for internal Microsoft development. Do not use it for external tasks. +#> +function Get-PipelineFeature { + [CmdletBinding(DefaultParameterSetName = 'Require')] + param( + [Parameter(Mandatory = $true)] + [string]$FeatureName + ) + + $featureValue = Get-TaskVariable -Name "DistributedTask.Tasks.$FeatureName" + + if (!$featureValue) { + Write-Debug "Feature '$FeatureName' is not set. Defaulting to 'false'" + return $false + } + + $boolValue = $featureValue.ToLowerInvariant() -eq 'true' + + Write-Debug "Feature '$FeatureName' = '$featureValue'. Processed as '$boolValue'" + + return $boolValue +} + ######################################## # Private functions. ######################################## diff --git a/powershell/VstsTaskSdk/VstsTaskSdk.psm1 b/powershell/VstsTaskSdk/VstsTaskSdk.psm1 index 20133885e..69a7b0419 100644 --- a/powershell/VstsTaskSdk/VstsTaskSdk.psm1 +++ b/powershell/VstsTaskSdk/VstsTaskSdk.psm1 @@ -44,6 +44,7 @@ Export-ModuleMember -Function @( 'Get-TaskVariable' 'Get-TaskVariableInfo' 'Set-TaskVariable' + 'Get-PipelineFeature' # Legacy find functions. 'Find-Files' # Localization functions. diff --git a/powershell/package-lock.json b/powershell/package-lock.json index 1bca8d69d..9db83dcd0 100644 --- a/powershell/package-lock.json +++ b/powershell/package-lock.json @@ -1,6 +1,6 @@ { "name": "powershell", - "version": "0.18.2", + "version": "0.19.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/powershell/package.json b/powershell/package.json index 0972b0655..6ec6095dd 100644 --- a/powershell/package.json +++ b/powershell/package.json @@ -1,5 +1,5 @@ { - "version": "0.18.2", + "version": "0.19.0", "private": true, "scripts": { "build": "node make.js build",