diff --git a/Tasks/NodeToolV0/Strings/resources.resjson/en-US/resources.resjson b/Tasks/NodeToolV0/Strings/resources.resjson/en-US/resources.resjson index ac0a8a82e7d4..88d5c48ca908 100644 --- a/Tasks/NodeToolV0/Strings/resources.resjson/en-US/resources.resjson +++ b/Tasks/NodeToolV0/Strings/resources.resjson/en-US/resources.resjson @@ -3,8 +3,11 @@ "loc.helpMarkDown": "[Learn more about this task](https://docs.microsoft.com/azure/devops/pipelines/tasks/tool/node-js) or [see the Node documentation](https://nodejs.org/docs/latest/api/documentation.html)", "loc.description": "Finds or downloads and caches the specified version spec of Node.js and adds it to the PATH", "loc.instanceNameFormat": "Use Node $(versionSpec)", + "loc.input.label.versionSource": "Source of version", "loc.input.label.versionSpec": "Version Spec", "loc.input.help.versionSpec": "Version Spec of version to get. Examples: 6.x, 4.x, 6.10.0, >=6.10.0", + "loc.input.label.versionFilePath": "Path to the .nvmrc file", + "loc.input.help.versionFilePath": "File path to get version. Example: src/.nvmrc", "loc.input.label.checkLatest": "Check for Latest Version", "loc.input.help.checkLatest": "Always checks online for the latest available version that satisfies the version spec. This is typically false unless you have a specific scenario to always get latest. This will cause it to incur download costs when potentially not necessary, especially with the hosted build pool.", "loc.input.label.force32bit": "Use 32 bit version on x64 agents", diff --git a/Tasks/NodeToolV0/Tests/L0.ts b/Tasks/NodeToolV0/Tests/L0.ts index 3eef5e2c10a4..169c392126f6 100644 --- a/Tasks/NodeToolV0/Tests/L0.ts +++ b/Tasks/NodeToolV0/Tests/L0.ts @@ -73,4 +73,19 @@ describe('NodeTool Suite', function () { }, tr, done); }); + it('Read node version from file', (done: Mocha.Done) => { + this.timeout(5000); + + let tp: string = path.join(__dirname, 'L0ReadVersionFromFileSuccess.js'); + let tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); + + tr.run(); + + runValidations(() => { + assert(tr.succeeded, 'NodeTool should have succeeded.'); + assert(tr.stderr.length === 0, 'NodeTool should not have written to stderr'); + }, tr, done); + }); + + }); \ No newline at end of file diff --git a/Tasks/NodeToolV0/Tests/L0FirstDownloadSuccess.ts b/Tasks/NodeToolV0/Tests/L0FirstDownloadSuccess.ts index 1965a9760dcc..bcb30f530031 100644 --- a/Tasks/NodeToolV0/Tests/L0FirstDownloadSuccess.ts +++ b/Tasks/NodeToolV0/Tests/L0FirstDownloadSuccess.ts @@ -6,6 +6,7 @@ import path = require('path'); let taskPath = path.join(__dirname, '..', 'nodetool.js'); let tmr: tmrm.TaskMockRunner = new tmrm.TaskMockRunner(taskPath); +tmr.setInput('versionSource', 'spec'); tmr.setInput('versionSpec', '11.3.0'); tmr.setInput('checkLatest', 'false'); diff --git a/Tasks/NodeToolV0/Tests/L0GetsLatestVersion.ts b/Tasks/NodeToolV0/Tests/L0GetsLatestVersion.ts index 722e0c89ec2c..2026f903eecd 100644 --- a/Tasks/NodeToolV0/Tests/L0GetsLatestVersion.ts +++ b/Tasks/NodeToolV0/Tests/L0GetsLatestVersion.ts @@ -5,6 +5,7 @@ import path = require('path'); let taskPath = path.join(__dirname, '..', 'nodetool.js'); let tmr: tmrm.TaskMockRunner = new tmrm.TaskMockRunner(taskPath); +tmr.setInput('versionSource', 'spec'); tmr.setInput('versionSpec', '>=12.0.0'); tmr.setInput('checkLatest', 'true'); diff --git a/Tasks/NodeToolV0/Tests/L0ReadVersionFromFileSuccess.ts b/Tasks/NodeToolV0/Tests/L0ReadVersionFromFileSuccess.ts new file mode 100644 index 000000000000..587b1a8d93f9 --- /dev/null +++ b/Tasks/NodeToolV0/Tests/L0ReadVersionFromFileSuccess.ts @@ -0,0 +1,88 @@ +import ma = require('azure-pipelines-task-lib/mock-answer'); +import tmrm = require('azure-pipelines-task-lib/mock-run'); +import os = require('os'); +import path = require('path'); + +let taskPath = path.join(__dirname, '..', 'nodetool.js'); +let tmr: tmrm.TaskMockRunner = new tmrm.TaskMockRunner(taskPath); + +tmr.setInput('versionSource', 'fromFile'); +tmr.setInput('versionFilePath', 'src/.nvmrc'); +tmr.setInput('checkLatest', 'false'); + +let a: ma.TaskLibAnswers = { + "assertAgent": { + "2.115.1": true + }}; +tmr.setAnswers(a); + + +//Create assertAgent and getVariable mocks +const tl = require('azure-pipelines-task-lib/mock-task'); +const tlClone = Object.assign({}, tl); +tlClone.getVariable = function(variable: string) { + if (variable.toLowerCase() == 'agent.tempdirectory') { + return 'temp'; + } + return null; +}; +tlClone.assertAgent = function(variable: string) { + return; +}; +tmr.registerMock('azure-pipelines-task-lib/mock-task', tlClone); + +//create fs mock +tmr.registerMock('fs', { + readFileSync: function (path, options) { + if (path != 'src/.nvmrc') { + throw new Error(`reading wrong .nvmrc: '${[path]}'`); + } + + return '11.3.0'; + } +}); + +//Create tool-lib mock +tmr.registerMock('azure-pipelines-tool-lib/tool', { + isExplicitVersion: function(versionSpec) { + return false; + }, + findLocalTool: function(toolName, versionSpec) { + if (toolName != 'node') { + throw new Error('Searching for wrong tool'); + } + return false; + }, + evaluateVersions: function(versions, versionSpec) { + if (versionSpec !== '11.3.0') { + throw new Error(`Incorrect versionSpec: ${versionSpec}`); + } + return versionSpec; + }, + cleanVersion: function(version) { + return '11.3.0'; + }, + downloadTool(url) { + if (url === `https://nodejs.org/dist/v11.3.0/node-v11.3.0-win-${os.arch()}.7z` || + url === `https://nodejs.org/dist/v11.3.0/node-v11.3.0-${os.platform()}-${os.arch()}.tar.gz`) { + return 'location'; + } + else { + throw new Error('Incorrect URL'); + } + }, + extract7z(downloadPath, extPath, _7zPath) { + return 'extPath'; + }, + extractTar(downloadPath, extPath, _7zPath) { + return 'extPath'; + }, + cacheDir(dir, tool, version) { + return 'path to tool'; + }, + prependPath(toolPath) { + return; + } +}); + +tmr.run(); \ No newline at end of file diff --git a/Tasks/NodeToolV0/Tests/L0SecondDownloadSuccess.ts b/Tasks/NodeToolV0/Tests/L0SecondDownloadSuccess.ts index 9a3d629b0cdc..486f94bb4361 100644 --- a/Tasks/NodeToolV0/Tests/L0SecondDownloadSuccess.ts +++ b/Tasks/NodeToolV0/Tests/L0SecondDownloadSuccess.ts @@ -6,6 +6,7 @@ import path = require('path'); let taskPath = path.join(__dirname, '..', 'nodetool.js'); let tmr: tmrm.TaskMockRunner = new tmrm.TaskMockRunner(taskPath); +tmr.setInput('versionSource', 'spec'); tmr.setInput('versionSpec', '5.10.1'); tmr.setInput('checkLatest', 'false'); diff --git a/Tasks/NodeToolV0/Tests/L0ThirdDownloadSuccess.ts b/Tasks/NodeToolV0/Tests/L0ThirdDownloadSuccess.ts index 02888a9a9671..75db1bf3c7a2 100644 --- a/Tasks/NodeToolV0/Tests/L0ThirdDownloadSuccess.ts +++ b/Tasks/NodeToolV0/Tests/L0ThirdDownloadSuccess.ts @@ -6,6 +6,7 @@ import path = require('path'); let taskPath = path.join(__dirname, '..', 'nodetool.js'); let tmr: tmrm.TaskMockRunner = new tmrm.TaskMockRunner(taskPath); +tmr.setInput('versionSource', 'spec'); tmr.setInput('versionSpec', '0.12.18'); tmr.setInput('checkLatest', 'false'); diff --git a/Tasks/NodeToolV0/nodetool.ts b/Tasks/NodeToolV0/nodetool.ts index 5aedc4188380..c07cc95ad6c6 100644 --- a/Tasks/NodeToolV0/nodetool.ts +++ b/Tasks/NodeToolV0/nodetool.ts @@ -4,6 +4,7 @@ import * as restm from 'typed-rest-client/RestClient'; import * as telemetry from 'azure-pipelines-tasks-utility-common/telemetry'; import * as os from 'os'; import * as path from 'path'; +import * as fs from 'fs'; const force32bit: boolean = taskLib.getBoolInput('force32bit', false); let osPlat: string = os.platform(); @@ -12,10 +13,13 @@ let osArch: string = getArch(); async function run() { try { taskLib.setResourcePath(path.join(__dirname, 'task.json')); - let versionSpec = taskLib.getInput('versionSpec', true); + let versionSource = taskLib.getInput('versionSource', true); + let versionSpecInput = taskLib.getInput('versionSpec', versionSource == 'spec'); + let versionFilePathInput = taskLib.getInput('versionFilePath', versionSource == 'fromFile'); + let versionSpec = getNodeVersion(versionSource, versionSpecInput, versionFilePathInput); let checkLatest: boolean = taskLib.getBoolInput('checkLatest', false); await getNode(versionSpec, checkLatest); - telemetry.emitTelemetry('TaskHub', 'NodeToolV0', { versionSpec, checkLatest, force32bit }); + telemetry.emitTelemetry('TaskHub', 'NodeToolV0', { versionSource, versionSpec, checkLatest, force32bit }); } catch (error) { taskLib.setResult(taskLib.TaskResult.Failed, error.message); @@ -257,4 +261,11 @@ function getArch(): string { return arch; } +function getNodeVersion(versionSource: string, versionSpecInput: string, versionFilePathInput: string) { + if (versionSource == 'spec') + return versionSpecInput + + return fs.readFileSync(versionFilePathInput, { 'encoding': 'utf8' }); +} + run(); diff --git a/Tasks/NodeToolV0/task.json b/Tasks/NodeToolV0/task.json index 4eeee5ec43a3..488ec969494f 100644 --- a/Tasks/NodeToolV0/task.json +++ b/Tasks/NodeToolV0/task.json @@ -14,7 +14,7 @@ "version": { "Major": 0, "Minor": 210, - "Patch": 0 + "Patch": 1 }, "satisfies": [ "Node", @@ -25,13 +25,31 @@ "minimumAgentVersion": "2.182.1", "instanceNameFormat": "Use Node $(versionSpec)", "inputs": [ + { + "name": "versionSource", + "type": "radio", + "label": "Source of version", + "required": true, + "defaultValue": "spec", + "options": { + "spec": "Specify Node version", + "fromFile": "Get version from file" + } + }, { "name": "versionSpec", "type": "string", "label": "Version Spec", "defaultValue": "6.x", - "required": true, - "helpMarkDown": "Version Spec of version to get. Examples: 6.x, 4.x, 6.10.0, >=6.10.0" + "helpMarkDown": "Version Spec of version to get. Examples: 6.x, 4.x, 6.10.0, >=6.10.0", + "visibleRule": "versionSource = spec" + }, + { + "name": "versionFilePath", + "type": "string", + "label": "Path to the .nvmrc file", + "helpMarkDown": "File path to get version. Example: src/.nvmrc", + "visibleRule": "versionSource = fromFile" }, { "name": "checkLatest", diff --git a/Tasks/NodeToolV0/task.loc.json b/Tasks/NodeToolV0/task.loc.json index ecbca4fb8af9..1504fbb86d97 100644 --- a/Tasks/NodeToolV0/task.loc.json +++ b/Tasks/NodeToolV0/task.loc.json @@ -14,7 +14,7 @@ "version": { "Major": 0, "Minor": 210, - "Patch": 0 + "Patch": 1 }, "satisfies": [ "Node", @@ -25,13 +25,31 @@ "minimumAgentVersion": "2.182.1", "instanceNameFormat": "ms-resource:loc.instanceNameFormat", "inputs": [ + { + "name": "versionSource", + "type": "radio", + "label": "ms-resource:loc.input.label.versionSource", + "required": true, + "defaultValue": "spec", + "options": { + "spec": "Specify Node version", + "fromFile": "Get version from file" + } + }, { "name": "versionSpec", "type": "string", "label": "ms-resource:loc.input.label.versionSpec", "defaultValue": "6.x", - "required": true, - "helpMarkDown": "ms-resource:loc.input.help.versionSpec" + "helpMarkDown": "ms-resource:loc.input.help.versionSpec", + "visibleRule": "versionSource = spec" + }, + { + "name": "versionFilePath", + "type": "string", + "label": "ms-resource:loc.input.label.versionFilePath", + "helpMarkDown": "ms-resource:loc.input.help.versionFilePath", + "visibleRule": "versionSource = fromFile" }, { "name": "checkLatest",