Azure Blog DEVOPS IT insights PowerShell

How to Build an Azure Custom Build/Release Task

By integrating this REST API in, not only does it present how you can leverage AirTable and Azure, but how one can combine nearly any REST API out there into Azure DevOps.

Making a Custom Pipeline Task

Azure DevOps, the Microsoft answer offering a comprehensive improvement surroundings, has the power to create custom pipeline duties. These tasks are built utilizing NodeJS and developed using Typescript, which is a superset language of JavaScript initially developed by Microsoft. Take into account that this text, and some code examples within, assume you’re using PowerShell in your command line interface.

Right here we’re going to build an answer to learn from a given database inside AirTable. We will then take that returned knowledge and cross the knowledge to the subsequent steps within the pipeline. By integrating this REST API in, not solely does it present how one can leverage these two tools collectively, however how you can integrate just about any REST API on the market into Azure DevOps.



Download NodeJS for Windows, which is a JavaScript run-time surroundings. My personal suggestion is to install the LTS (long-term help) release which is 10.15.three at time of this writing (though any current model ought to work fantastic). Installing with the defaults will work perfectly high-quality for this.

This package deal will additionally set up NPM (Node Package deal Supervisor), which we use to install the opposite prerequisite packages to develop the duty.

After you run by way of the install, you’ll be able to verify that it put in properly by operating the following at the command line:

node -v

npm -v

Observe: You could want to improve NPM in case you have it previously put in an older version or would really like to run with the newest version.

npm install -g [email protected]


Set up Typescript, this works only when you’ve got NodeJS and NPM installed already, it will install Typescript globally (by way of the -g command).

npm set up -g typescript

NODE CLI for Azure DevOps (TFX-CLI)

This can be a command line device for interacting with Azure DevOps and Microsoft Staff Basis Server.

npm install -g tfx-cli

Create a Custom Task

  1. Setup the build surroundings and conditions

Create Build and Package deal Listing

# Create Package deal Directory

New-Merchandise -Identify “buildRelease” -Sort Listing

Set-Location buildRelease

Set up Packages

# Initialize NPM (node_modules) and Install Conditions

npm init -y

npm set up azure-pipelines-task-lib –save

npm install typed-rest-client –save

# Both of the gadgets under are for definitions for Node and Q (helper package deal)

npm install @varieties/node –save-dev

npm install @varieties/q –save-dev

Notice: We are putting in the typed-rest-client as a result of it provides us an straightforward HTTP shopper to perform REST API calls within our activity.

Setup Typescript

# Make certain we don’t commit the node_modules and it’s many hundreds of information

echo node_modules > .gitignore

# Initialize Typescript

tsc –init

# Change Typescript Goal Language to ES6 from ES5. ES6 is the most recent iteration of the Javascript language syntax and performance and has many benefits for ease of use

((Get-Content -Path ‘.tsconfig.json’ -Raw) -replace ‘”es5″‘,’”es6″‘) | Set-Content -Path ‘.tsconfig.json’

2. Create the task .json file in our buildRelease working folder by way of the under script:

This defines our activity, the entry point and in addition what inputs we require. In our case, we’re going to outline an AirTable process that we capture the API key and the bottom URL for a REST name.

# Only required to have a unqiue GUID

$GUID = (New-Guid).Guid

$Identify         = “get-airtable-data”

$FriendlyName = “Retrieve AirTable Data”

$Description  = “This is a task to retrieve Airtable Data.”

$Writer       = “Adam Bertram”

$JSON = @”

“id”: “$GUID”,

“name”: “$Name”,

“friendlyName”: “$FriendlyName”,

“description”: “$Description”,

“helpMarkDown”: “”,

“category”: “Utility”,

“author”: “$Author”,


“Major”: zero,

“Minor”: 1,

“Patch”: 0






“instanceNameFormat”: “Retrieving $(baseurl) from AirTable”,


“name”: “baseurl”,

“type”: “string”,

“label”: “Base URL”,

“defaultValue”: “”,

“required”: true,

“helpMarkDown”: “The base URL for the REST API call within AirTable”


“name”: “apikey”,

“type”: “string”,

“label”: “API Key”,

“inputMode”: “passwordbox”,

“isConfidential”: true,

“defaultValue”: “”,

“required”: true,

“helpMarkDown”: “AirTable API Key”




“target”: “index.js”

$JSON | Set-Content -Path “./task.json”

three. Create the ts file that really accommodates the logic of our new process. For this AirTable activity, we’ll save the JSON output of the results to a variable that can be handed on to the subsequent activity.

$boilerplate = @”
import tl = require(‘azure-pipelines-task-lib/activity’);
import httpc = require(‘typed-rest-client/HttpClient’);

async perform run()
const baseURL: string = tl.getInput(‘baseurl’, true);
const APIKey: string = tl.getInput(‘apikey’, true);

if (baseURL == ‘dangerous’)
setResult(tl.TaskResult.Failed, ‘Dangerous input was given’);

if (APIKey == ‘dangerous’)
tl.setResult(tl.TaskResult.Failed, ‘Dangerous input was given’);


let httpClient: httpc.HttpClient = new httpc.HttpClient(‘Check’, []);

let outcome = await httpClient.get(baseURL,
‘Accept’: ‘software/json’,
‘Authorization’: ‘Bearer ‘ + APIKey

let physique: string = await end result.readBody();
let obj:any = JSON.parse(physique);


tl.setVariable(“AIRTABLERESULT”, body, false);

catch (err)
tl.setResult(tl.TaskResult.Failed, err.message);


$boilerplate | Set-Content material -Path “./index.ts”

4. Compile the Typescript file in JavaScript for deployment. This command takes our ts file and compiles it to js. This may even output any obvious errors upon compiling.


Verify the Task

We set environmental variables as that’s how knowledge is handed around inside the construct environments. Upon operating our compiled index.js file, it can learn within the environmental variables and output the results.


node index.js

Instance Results:

##vso[task.debug]loading inputs and endpoints
##vso[task.debug]loading INPUT_APIKEY
##vso[task.debug]loading INPUT_BASEURL
##vso[task.debug]loaded 2
fields: Identify: ‘Report 2’, Value: ‘Worth 2’ ,
createdTime: ‘2019-04-25T04:16:25.000Z’ ,
id: ‘recP6d01urYlVQOS5’,
fields: Identify: ‘Report 1’, Value: ‘Worth 1’ ,
createdTime: ‘2019-04-25T04:16:25.000Z’ ,
id: ‘recPyPXYbvTScUFn1’,
fields: Identify: ‘Report three’, Value: ‘Worth three’ ,
createdTime: ‘2019-04-25T04:16:25.000Z’ ]##vso[task.debug]set AIRTABLERESULT=“records”:[“id”:”recLpzf2VZ6jyGIbm”,”fields”:“Name”:”Report 2″,”Worth”:”Worth 2″,”createdTime”:”2019-04-25T04:16:25.000Z”,“id”:”recP6d01urYlVQOS5″,”fields”:“Name”:”Report 1″,”Worth”:”Value 1″,”createdTime”:”2019-04-25T04:16:25.000Z”,“id”:”recPyPXYbvTScUFn1″,”fields”:“Name”:”Document 3″,”Worth”:”Worth three″,”createdTime”:”2019-04-25T04:16:25.000Z”]##vso[task.setvariable variable=AIRTABLERESULT;issecret=false;]“records”:[“id”:”recLpzf2VZ6jyGIbm”,”fields”:“Name”:”Document 2″,”Value”:”Worth 2″,”createdTime”:”2019-04-25T04:16:25.000Z”,“id”:”recP6d01urYlVQOS5″,”fields”:“Name”:”Report 1″,”Value”:”Worth 1″,”createdTime”:”2019-04-25T04:16:25.000Z”,“id”:”recPyPXYbvTScUFn1″,”fields”:“Name”:”Report 3″,”Worth”:”Worth three″,”createdTime”:”2019-04-25T04:16:25.000Z”]

Package deal and Publish the Task

To publish this extension we’d like to define our manifest file taht helps to define the place and in what instances our extension will present up.

Manifest Documentation

Key Notes

  • The writer should match the writer you create within Azure DevOps market
  • Information → Path should level to our build directory
  • Contributions → Properties → Identify must also point to our construct listing
  • The vss-extension.json file lives in the root directory, one up from the construct listing

$Publisher = “adam-bertram” $PublisherFriendly = “Adam Bertram” $Description = “Build and Release Tools”
$Manifest = @” “manifestVersion”: 1,  “id”: “build-release-task”,  “name”: “$PublisherFriendly Build and Release
Tools”, “version”: “0.0.1”, “publisher”: “$Publisher”,  “targets”: [    “id”: “Microsoft.VisualStudio.Services”    ],
“description”: “$Description”, “categories”: [ “Azure Pipelines”, “Build and release” ], “tags”: [ “release”, “build” ],
“files”: [ “path”: “buildRelease” ], “contributions”:[“id”:”custom-build-release-task””sort”:”msvss-distributed-[“id”:”custom-build-release-task””sort”:”msvss-distributed-[“id”:”custom-build-release-task””sort”:”msvss-distributed-[“id”:”custom-build-release-task””sort”:”msvss-distributed-
process.process”, “targets”: [ “ms.vss-distributed-task.tasks” ], “properties”: “name”: “buildRelease” ] “@

Have to be in root

Set-Location .. $Manifest | Set-Content material -Path “./vss-extension.json”

Package deal the Extension

This can package deal up the extension right into a .vsix file that we will use to upload to the Marketplace.

Observe: Every time we’d like to package deal a model, it’s required we rev the version. It’s best to add the –rev-version parameter in order that we routinely achieve this every time.

tfx extension create –manifest-globs vss-extension.json –rev-version

Create a Writer

It’s required that extensions are identified from a provider, Microsoft’s included. When you haven’t created one but, achieve this with the following steps.

  1. Sign up to the Visual Studio Market Publishing Portal
  2. Enter in the Supplier particulars:
    • Create an identifier in your writer: mycompany-myteam
    • Specify a show identify: My Workforce
  3. Click Create

Add Your Extension

As soon as a publisher has been created, you can now add your packaged extension. To do so, click on New extension → Azure DevOps.

You’ll be prompted to either Drag and Drop or add the .vsix file that was created earlier by packaging our new extension.

Share and Set up Your Extension

To allow an organization to use your new extension, share it with one or more so that you may set up and check your extension.

  1. Proper-click on your extension and select Share, enter in your organization identifier
  2. Navigate to your group within Azure DevOps, click on the Market icon in the higher right corner and click on Handle Extensions
  3. Click on the identify of the Extension to navigate to it within the Market, once there click on the Get it free button.
  4. Choose the organization from the drop-down menu and click on Set up

After the extension is put in, you will be able to discover this process inside the Build and Launch duties listing. You’ll be able to add one, check the inputs and see the output inside the log information.