I develop all our task extensions in PowerShell, now I start to translate my first extension into TypeScript. The extension is a small task which should run in build or release pipelines. The task should get deployed to a Azure DevOps Server 2020.1 (on prem).
- Visual Studio Code
- Node (v14.15.4)
- TypeScript (Version 4.1.3)
- ts-node (v9.1.1)
- mocha (8.2.0)
- ts-mocha (8.0.0)
- azure-pipelines-task-lib (2.12.0)
{
"version": "0.2.0",
"configurations": [
{
"args": ["task/index.ts", "--Template", "Custom"],
"internalConsoleOptions": "openOnSessionStart",
"name": "Run TypeScript",
"request": "launch",
"runtimeArgs": ["--nolazy", "-r", "ts-node/register/transpile-only"],
"skipFiles": ["<node_internals>/**"],
"type": "pwa-node"
}
]
}
Start up command:
node.exe --nolazy -r ts-node/register/transpile-only task/index.ts --Template Custom
At runtime, when the tl.getInput function with required true get executed, the debugging stop immediately without any response (no error, no output).
App.ts:
import tl = require("azure-pipelines-task-lib/task");
export const App = {
Param: {
Test: "Here",
Template: tl.getInput("Template", true),
}
}
Index.ts (entry point):
import { App } from "./app";
function run() {
console.log("Hello");
console.log(App.Param.Test);
}
run();
Output (just nothing):
Index.ts (modified):
import { App } from "./app";
function run() {
console.log("Hello");
// console.log(App.Param.Test);
}
run();
Output (modified):
Hello
obviously it stops because the required variable Template get not passed to the application.
tl.getInput?It is totally clear that running azure-pipelines-task-lib without a Azure DevOps environment run into issues. But I was hoping that it is possible to mockup the required pipeline variables and run this library locally. If using azure-pipelines-task-lib means that you have to deploy the extension and run it in a pipeline to test, it get kind of komplex to develop tasks with it, or?
I found the deprecated repository about vsts-task-lib. In azure-pipelines-tasks/docs/debugging.md is manual to debug that library. The author of Debugging TypeScript Tasks in VS Code describe an example launch.json configuration and I modify it for my usecase:
{
"name": "Launch tar.gz",
"type": "node",
"request": "launch",
"program": "${workspaceFolder}/dist/task/index.js",
"stopOnEntry": false,
"args": [],
"cwd": "${workspaceRoot}/task",
"preLaunchTask": "tsc: build - tsconfig.json",
"runtimeExecutable": null,
"runtimeArgs": ["--nolazy"],
"env": {
"NODE_ENV": "development",
"INPUT_Separator": ";",
"BUILD_SOURCESDIRECTORY": "C:\\agents\\latest\\_work\\21\\s"
},
"sourceMaps": true,
"outFiles": ["${workspaceRoot}/dist"]
}
I can confirm that it is possible to start up debugging and the tl.getInput("Separator") will return ;.
With the help of Debugging TypeScript Tasks in VS Code I was able to do the following things:
tl.getInput from import tl = require("azure-pipelines-task-lib/task")tl.getVariable from import tl = require("azure-pipelines-task-lib/task")new azdev.WebApi from import * as azdev from "azure-devops-node-api"getBuildApi from import * as ba from "azure-devops-node-api/BuildApi"{
"name": "Run TypeScript",
"type": "pwa-node",
"request": "launch",
"internalConsoleOptions": "openOnSessionStart",
"stopOnEntry": false,
// path to your ts file
"args": ["index.ts"],
"cwd": "${workspaceRoot}/task",
"runtimeArgs": ["--nolazy", "-r", "ts-node/register/transpile-only"],
"env": {
"NODE_ENV": "development",
// param (enter your input params here!)
"INPUT_WebhookUrl": "MyVariables",
"INPUT_Template": "Empty",
"INPUT_Json": "{\"text\":\"I am a test message\",\"attachments\":[{\"text\":\"And here’s an attachment!\"}]}",
"INPUT_Separator": ";",
// env
"AGENT_JOBSTATUS": "Succeeded",
"AGENT_NAME": "MyAgent",
"BUILD_BUILDID": "5",
"BUILD_BUILDNUMBER": "20210108.1",
"BUILD_REASON": "Scheduled",
"BUILD_REPOSITORY_NAME": "MyRepo",
"BUILD_SOURCEBRANCHNAME": "master",
"BUILD_SOURCEVERSION": "122a24f",
"BUILDCONFIGURATION": "Debug",
"BUILDPLATFORM": "Any CPU",
"SYSTEM_ACCESSTOKEN": "",
"SYSTEM_DEFINITIONNAME": "MyDefinitionName",
"SYSTEM_TEAMFOUNDATIONSERVERURI": "https://myurl.de/mycollection/",
"SYSTEM_TEAMPROJECT": "PSItraffic",
// debug
"DEBUG_PAT": "my debug pat"
},
"skipFiles": ["<node_internals>/**"]
}
Read param & env: app.ts
import tl = require("azure-pipelines-task-lib/task");
export const App = {
// ------------------------------------------------------------ param
Param: {
WebhookUrl: tl.getDelimitedInput("WebhookUrl", "\n", true),
Template: tl.getInput("Template", true)
},
// ------------------------------------------------------------ env
Env: {
Agent: {
Jobstatus: getVariable("AGENT_JOBSTATUS"),
Name: getVariable("AGENT_NAME"),
},
...
System: {
AccessToken: getVariable("SYSTEM_ACCESSTOKEN"),
DefinitionName: getVariable("SYSTEM_DEFINITIONNAME"),
TeamFoundationServerUri: getVariable("SYSTEM_TEAMFOUNDATIONSERVERURI"),
TeamProject: getVariable("SYSTEM_TEAMPROJECT"),
},
// ------------------------------------------------------------ debug
Debug: {
Pat: getVariable("DEBUG_PAT"),
},
}
function getVariable(name: string): string {
// get variable
let v = tl.getVariable(name);
if (v === undefined) return "";
return v;
}
connect to azure devops server: rest.ts
import { App } from "./app";
import * as azdev from "azure-devops-node-api";
import * as ba from "azure-devops-node-api/BuildApi";
export class Rest {
static AuthHanlder: IRequestHandler = Rest.Auth();
static Connection: azdev.WebApi = new azdev.WebApi(App.Env.System.TeamFoundationServerUri, Rest.AuthHanlder);
static Auth(): IRequestHandler {
// auth
if (App.Env.System.AccessToken === "") return azdev.getPersonalAccessTokenHandler(App.Debug.Pat);
// no sure if this works on production
return azdev.getBearerHandler(App.Env.System.AccessToken);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With