Azure devops 调试Azure DevOps任务扩展(TypeScript)

Azure devops 调试Azure DevOps任务扩展(TypeScript),azure-devops,azure-pipelines-build-task,Azure Devops,Azure Pipelines Build Task,我在PowerShell中开发了所有任务扩展,现在我开始将第一个扩展翻译成TypeScript。扩展是一个小任务,应该在构建或发布管道中运行。该任务应部署到Azure DevOps Server 2020.1(在prem上) 准备工作 教程 我遵循教程并用它构建了一个示例应用程序 我克隆并签出编程风格 系统设置 Launch.json Index.ts(入口点): 输出(无): Index.ts(修改): 输出(修改): 显然,它会停止,因为所需的变量Template没有传递给应用程序

我在
PowerShell
中开发了所有任务扩展,现在我开始将第一个扩展翻译成
TypeScript
。扩展是一个小任务,应该在构建或发布管道中运行。该任务应部署到Azure DevOps Server 2020.1(在prem上)


准备工作 教程
  • 我遵循教程并用它构建了一个示例应用程序
  • 我克隆并签出编程风格
系统设置
Launch.json
Index.ts
(入口点):

输出(无):

Index.ts
(修改):

输出(修改):

显然,它会停止,因为所需的变量
Template
没有传递给应用程序


问题
  • 有没有办法调试azure devops任务扩展
  • 是否可以通过
    tl.getInput
    传递参数并加载它们
  • 如何开发azure devops任务扩展,是否有最先进的技术或完整的指南
很明显,在没有azure DevOps环境的情况下运行
azure pipelines任务库
会遇到问题。但是我希望可以模拟所需的管道变量并在本地运行此库。
如果使用
azure管道任务库
意味着您必须部署扩展并在管道中运行它以进行测试,那么使用它开发任务会有点像komplex,或者


编辑1: 我发现不推荐使用的存储库大约。在
azure pipelines tasks/docs/debug.md
中,手动调试该库。本文作者描述了一个示例
launch.json
配置,我根据自己的用例修改了它:

{
      "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"]
    }
我可以确认可以启动调试,并且
tl.getInput(“分隔符”)
将返回

有没有办法调试azure devops任务扩展

是的,根据文章“”中的说明,在安装所有必需的库和依赖项并添加所有必需的任务实现文件后,您可以使用PowerShell或其他Shell。默认情况下,任务以调试模式运行。见下面我分享的例子

是否可以通过tl.getInput传递参数并加载它们

当然,您可以将tl.getInput的值作为参数传递。见下面我分享的例子

如何开发azure devops任务扩展,是否有最先进的技术或完整的指南

目前,关于DevOps扩展的Microsoft文档是我们开发DevOps扩展的最佳指南

按照您的情况,我也会在我这边进行测试,下面是我使用的主要源代码:

  • task.json
{
“$schema”:”https://raw.githubusercontent.com/Microsoft/azure-pipelines-task-lib/master/tasks.schema.json",
“id”:“dc7322d8-6c98-4be7-91c9-dcbf7f4df7dd”,
“名称”:“buildAndReleaseTask”,
“friendlyName”:“构建和发布任务”,
“描述”:“测试创建生成和发布任务”,
“帮助标记”:“,
“类别”:“实用程序”,
“作者”:“光明冉”,
“版本”:{
“主要”:0,
“小调”:1,
“补丁”:0
},
“instanceNameFormat”:“Echo$(用户名)”,
“投入”:[
{
“名称”:“用户名”,
“类型”:“字符串”,
“标签”:“用户名”,
“defaultValue”:“,
“必需”:正确,
“帮助标记”:“用户名”
}
],
“执行”:{
“节点10”:{
“目标”:“index.js”
}
}
}
  • App.ts(与您的几乎相同)
  • index.ts(与您的几乎相同)
  • 编译并运行任务的结果

从结果中,您可以看到这两个参数可以正常传递。

在我的帮助下,我可以做以下事情:

  • 从导入tl=require(“azure管道任务库/任务”)
  • 从导入tl=require(“azure管道任务库/任务”)
  • 从“Azure DevOps节点api”以azdev身份从
    导入*连接到Azure DevOps服务器,并使用
    新建azdev.WebApi
  • 从“azure devops节点api/BuildApi”
  • 直接使用TypeScript运行并调试应用程序,无需JavaScript翻译

  • launch.json 连接到azure devops服务器:
    rest.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;
    }
    
    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);
      }
    }
    

    嗨@MarTin,很高兴你解决了这个问题,谢谢你分享你的经验。你能把你的答案标记为这个题目的答案吗?这可能对那些正在寻找类似问题解决方案的人非常有帮助。
    import { App } from "./app";
    
    function run() {
      console.log("Hello");
      console.log(App.Param.Test);
    }
    
    run();
    
    import { App } from "./app";
    
    function run() {
      console.log("Hello");
      // console.log(App.Param.Test);
    }
    
    run();
    
    Hello
    
    {
          "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"]
        }
    
    import tl = require("azure-pipelines-task-lib/task");
    export const App = {
      Param: {
          Here: "Here",
          UserName: tl.getInput("UserName", true),
      }
    }
    
    import { App } from "./App";
    
    function run() {
      console.log("Hello,", App.Param.UserName);
      console.log("Look", App.Param.Here);
    }
    
    run();
    
    tsc
    $env:INPUT_USERNAME="xxxx"
    node index.js
    
    {
      "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>/**"]
    }
    
    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;
    }
    
    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);
      }
    }