diff --git a/node/README.md b/node/README.md index 5cb32dd49..9a6f53ee5 100644 --- a/node/README.md +++ b/node/README.md @@ -17,17 +17,32 @@ Documentation: [TypeScript API](https://github.com/microsoft/azure-pipelines-tas Guidance: [Finding Files](https://github.com/microsoft/azure-pipelines-task-lib/blob/master/node/docs/findingfiles.md), [Minimum agent version](https://github.com/microsoft/azure-pipelines-task-lib/blob/master/node/docs/minagent.md), [Proxy](https://github.com/microsoft/azure-pipelines-task-lib/blob/master/node/docs/proxy.md), [Certificate](https://github.com/microsoft/azure-pipelines-task-lib/blob/master/node/docs/cert.md) -## Node 10 Upgrade Notice +## Node Runtime Support -Azure DevOps is currently working to establish Node 10 as the new preferred runtime for tasks, upgrading from Node 6. -Relevant work is happening in the `master` branch and the major version should be used with Node 10 is 3. -Previous major version is stored in the `releases/2.x` +Azure Pipelines supports multiple Node.js runtimes for task execution: -### Upgrading to Node 10 +* **Node 6** - Supported +* **Node 10** - Supported +* **Node 16** - Supported +* **Node 20** - Current recommended version +* **Node 24** - Latest version with modern JavaScript features -Upgrading your tasks from Node 6 should be relatively painless, however there are some things to note: -* Typescript has been upgraded to TS 4. Older versions of TS may or may not work with Node 14 or the 3.x branch. We recommend upgrading to TS 4 when upgrading to task-lib 3.x. -* Node has made some changes to `fs` between Node 6 and Node 10. It is worth reviewing and testing your tasks thoroughly before publishing updates to Node 10. +### Node Version Selection + +The Node runtime used depends on the `execution` handler specified in your task's `task.json`: +* `Node` - Uses Node 6 +* `Node10` - Uses Node 10 +* `Node16` - Uses Node 16 +* `Node20_1` - Uses Node 20 (Note: handler name includes _1 suffix) +* `Node24` - Uses Node 24 + +### Upgrading to Newer Node Versions + +When upgrading your tasks to newer Node versions: +* **TypeScript**: Ensure you're using a compatible TypeScript version (TS 4.0+ for Node 10+, TS 5.0+ for Node 20+, TS 5.7+ for Node 24) +* **Dependencies**: Review and update npm dependencies for compatibility with the target Node version +* **Testing**: Thoroughly test your tasks with the new Node runtime before publishing +* **Breaking Changes**: Review Node.js release notes for breaking changes between versions (especially `fs` module changes) ## Reference Examples diff --git a/node/docs/minagent.md b/node/docs/minagent.md index 2d30abfc0..f0acfd5c2 100644 --- a/node/docs/minagent.md +++ b/node/docs/minagent.md @@ -30,6 +30,10 @@ Use the details below to determine when specific agent features were added: - Added in 2.144.0. Used node v10.x * `node16` handler - Added in 2.206.1. Used node v16.x +* `node20` handler + - Added in 2.214.1. Used node v20.x +* `node24` handler + - Added in 3.250.0. Uses node v24.x * `powershell3` handler - Added in 1.95.1 - Updated in 1.97 to propagate `Data` property for endpoints diff --git a/node/docs/nodeVersioning.md b/node/docs/nodeVersioning.md index 91a805ce1..87b0dabd8 100644 --- a/node/docs/nodeVersioning.md +++ b/node/docs/nodeVersioning.md @@ -2,9 +2,9 @@ ## Agent Node Handler -The agent currently has 3 different node handlers that it can use to execute node tasks: Node 6, Node 10, Node 16. +The agent currently has multiple node handlers that it can use to execute node tasks: Node 6, Node 10, Node 16, Node 20, and Node 24. The handler used depends on the `execution` property specified in the tasks `task.json`. -If the `execution` property is specified to be `Node`, the task will run on the Node 6 handler, for `Node10` it will run on the Node 10 handler, for `Node16` it will run on the Node 16 handler. +If the `execution` property is specified to be `Node`, the task will run on the Node 6 handler, for `Node10` it will run on the Node 10 handler, for `Node16` it will run on the Node 16 handler, for `Node20_1` it will run on the Node 20 handler, and for `Node24` it will run on the Node 24 handler. ## Mock-test Node Handler @@ -16,5 +16,5 @@ If this version of node is not found on the path, the library downloads the appr ### Behavior overrides -To specify a specific version of node to use, set the `nodeVersion` optional parameter in the `run` function of the `MockTestRunner` to the integer major version (e.g. `mtr.run(5)`). +To specify a specific version of node to use, set the `nodeVersion` optional parameter in the `run` function of the `MockTestRunner` to the integer major version (e.g. `mtr.run(20)` for Node 20, `mtr.run(24)` for Node 24). To specify the location of a `task.json` file, set the `taskJsonPath` optional parameter in the `MockTestRunner` constructor to the path of the file (e.g. `let mtr = new mt.MockTaskRunner('', ''`). \ No newline at end of file diff --git a/node/mock-test.ts b/node/mock-test.ts index 56e432879..7826075b9 100644 --- a/node/mock-test.ts +++ b/node/mock-test.ts @@ -166,6 +166,7 @@ export class MockTestRunner { private async getNodePath(nodeVersion?: number): Promise { const version: number = nodeVersion || this.getNodeVersion(); const versions = { + 24: 'v24.10.0', 20: 'v20.13.1', 16: 'v16.20.2', 10: 'v10.24.1', @@ -174,7 +175,7 @@ export class MockTestRunner { const downloadVersion: string = versions[version]; if (!downloadVersion) { - throw new Error('Invalid node version, must be 6, 10, 16 or 20 (received ' + version + ')'); + throw new Error('Invalid node version, must be 6, 10, 16, 20 or 24 (received ' + version + ')'); } // Install node in home directory if it isn't already there. diff --git a/node/package-lock.json b/node/package-lock.json index f663f16ef..573327944 100644 --- a/node/package-lock.json +++ b/node/package-lock.json @@ -1,6 +1,6 @@ { "name": "azure-pipelines-task-lib", - "version": "5.2.1", + "version": "5.2.2", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -909,4 +909,4 @@ "dev": true } } -} +} \ No newline at end of file diff --git a/node/package.json b/node/package.json index be52667f0..23e73de48 100644 --- a/node/package.json +++ b/node/package.json @@ -1,6 +1,6 @@ { "name": "azure-pipelines-task-lib", - "version": "5.2.1", + "version": "5.2.2", "description": "Azure Pipelines Task SDK", "main": "./task.js", "typings": "./task.d.ts", diff --git a/node/test/fakeTasks/node24task/entry.js b/node/test/fakeTasks/node24task/entry.js new file mode 100644 index 000000000..608a3c294 --- /dev/null +++ b/node/test/fakeTasks/node24task/entry.js @@ -0,0 +1,2 @@ +// Minimal entry point for Node 24 task testing +console.log('Node 24 task entry point'); diff --git a/node/test/fakeTasks/node24task/task.json b/node/test/fakeTasks/node24task/task.json new file mode 100644 index 000000000..3f6bcb41c --- /dev/null +++ b/node/test/fakeTasks/node24task/task.json @@ -0,0 +1,21 @@ +{ + "id": "id", + "name": "Node24Task", + "execution": { + "Node": { + "target": "usedotnet.js" + }, + "Node10": { + "target": "usedotnet.js" + }, + "Node16": { + "target": "usedotnet.js" + }, + "Node20_1": { + "target": "usedotnet.js" + }, + "Node24": { + "target": "usedotnet.js" + } + } +} diff --git a/node/test/mocktests.ts b/node/test/mocktests.ts index 4d9ada5d1..9722498db 100644 --- a/node/test/mocktests.ts +++ b/node/test/mocktests.ts @@ -348,6 +348,16 @@ describe('Mock Tests', function () { await Promise.resolve() }) + it('MockTest handles node 24 tasks correctly', async function () { + this.timeout(30000); + const runner = await (new mtm.MockTestRunner).LoadAsync(path.join(__dirname, 'fakeTasks', 'node24task', 'entry.js')); + const nodePath = runner.nodePath; + assert(nodePath, 'node path should have been correctly set'); + const version = ncp.execSync(nodePath + ' -v').toString().trim(); + assert(semver.satisfies(version, '24.x'), 'Downloaded node version should be Node 24 instead of ' + version); + await Promise.resolve() + }) + it('MockTest handles node tasks correctly by async call', async () => { this.timeout(30000); const runner = await (new mtm.MockTestRunner).LoadAsync(path.join(__dirname, 'fakeTasks', 'node16task', 'entry.js')); diff --git a/tasks.schema.json b/tasks.schema.json index d037a45e8..a08501c79 100644 --- a/tasks.schema.json +++ b/tasks.schema.json @@ -394,6 +394,9 @@ "additionalProperties": false, "description": "Execution options for this task (on Pre-Job stage)", "properties": { + "Node24": { + "$ref": "#/definitions/executionObject" + }, "Node20_1": { "$ref": "#/definitions/executionObject" }, @@ -419,6 +422,9 @@ "additionalProperties": false, "description": "Execution options for this task", "properties": { + "Node24": { + "$ref": "#/definitions/executionObject" + }, "Node20_1": { "$ref": "#/definitions/executionObject" }, @@ -444,6 +450,9 @@ "additionalProperties": false, "description": "Execution options for this task (on Post-Job stage)", "properties": { + "Node24": { + "$ref": "#/definitions/executionObject" + }, "Node20_1": { "$ref": "#/definitions/executionObject" },