Last Updated: 9 September 2022
You may have alread seen our article on creating custom build tasks using Powershell and a custom .Net Core / .Net 6 CLI tool written in C#. It is also possible to create a true cross-platform custom build task that uses node.js and Typescript instead of the Powershell / C# combination described in that article.
It is possible to package and publish your custom tasks to make them available for installation into any Azure DevOps organization, or to just the organizations you choose. This is appropriate if, for example, you intend to allow a more self-service approach to your DevOps teams, or if you want to share your tasks publicly. This guide assumes you already have node.js installed, and have the TFX extension. See our Powershell & C# custom task guide for how to do this.
Create a folder called 'MyCustomTask', then from a command line within that directory, initialize your task:
npm init --yes
npm install @types/node --save-dev
npm install @types/q --save-dev
npm install mocha --save-dev -g
npm install sync-request --save-dev
npm install @types/mocha --save-dev
npm install azure-pipelines-task-lib --save
npm install typescript@4.0.2 -g --save-dev
echo node_modules > .gitignore
tsc --init --target es6
This adds some package dependencies, including a utility task library provided by Microsoft. This library provides functions to interact with Azure DevOps and provides logging, ways to with user parameters, and the ability to indicate success/failure. It also provides functions to run external tools and commands. If you are running these commands from Powershell and get an error from the 'tsc' comnmand around execution policies, run the following and retry:
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
Create a file called task.json, and save it into your MyCustomTask folder. This is broadly the same as the one we previously discussed in the Powershell / C# example, but specifies a node.js target instead:
{
"$schema": "https://raw.githubusercontent.com/Microsoft/azure-pipelines-task-lib/master/tasks.schema.json",
"id": "YOUR-GENERATED-GUID-HERE",
"name": "MyCustomTask",
"friendlyName": "Demo Task",
"description": "This is a demo task.",
"helpMarkDown": "For more information about this task, visit www.example.com",
"category": "Azure Pipelines",
"author": "Joe Bloggs",
"version": {
"Major": 1,
"Minor": 0,
"Patch": 0
},
"instanceNameFormat": "MyCustomTask",
"inputs": [
{
"name": "someString",
"type": "string",
"label": "Some string",
"required": true,
"helpMarkDown": "This is an example string input"
},
{
"name": "anotherString",
"type": "string",
"label": "Another string",
"required": false,
"helpMarkDown": "This is another example",
"defaultValue": "Hello World"
},
],
"execution": {
"Node10": {
"target": "index.js"
}
}
}
Create a script using the scaffolding template below, this will be where the bulk of your logic will go:
import tl = require('azure-pipelines-task-lib/task');
import tr = require('azure-pipelines-task-lib/toolrunner');
async function run() {
try {
console.log('##[warning] This is how to log a warning');
const someString: string | undefined = tl.getInput('someString', true);
console.log('Some String: ', someString);
const anotherString: string | undefined = tl.getInput('anotherString', false);
console.log('Another String: ', anotherString);
console.log('##[error] This is how to log an error');
}
catch (err) {
tl.setResult(tl.TaskResult.Failed, err.message);
}
}
run();
Compile your .ts file into .js using the following command (run from inside the folder you created above). If successful, you will now also have an index.js file present:
tsc
Use the following commands to upload your new task to Azure DevOps:
tfx login --authType pat
tfx build tasks upload --task-path C:\temp\MyCustomTask\Task
For further information on installing node.js, the TFX command line tool, and setting up a Personal Access Token to authenticate with Azure DevOps, see our original article on custom build tasks with Powershell and C#.