添加自定义管道任务扩展

Azure DevOps Services | Azure DevOps Server 2022 - Azure DevOps Server 2019

了解如何在 Azure DevOps 中为组织的自定义生成或发布任务安装扩展。 有关详细信息,请参阅什么是 Azure Pipelines?

注意

本文介绍基于代理的扩展中的代理任务。 有关服务器任务和基于服务器的扩展的详细信息,请参阅 服务器任务 GitHub 文档

先决条件

若要为 Azure DevOps 创建扩展,需要以下软件和工具。

软件/工具 信息
Azure DevOps 组织 创建一个组织
文本编辑器 对于许多过程,我们使用 Visual Studio Code,它提供 Intellisense 和调试支持。 下载最新版本
Node.js 下载最新版本
npmjs.com 4.0.2 或更高版本 TypeScript 编译器。 下载最新版本
tfx-cli 使用 适用于 Azure DevOps 的跨平台 CLI 打包扩展。 using,Node.js npm的组件,通过运行 npm i -g tfx-cli
Azure DevOps 扩展 SDK 安装 azure-devops-extension-sdk 包
home项目的目录 home完成本文中的步骤后,生成或发布任务扩展的目录应如以下示例所示。
|--- README.md    
|--- images                        
    |--- extension-icon.png  
|--- buildandreleasetask            // where your task scripts are placed
|--- vss-extension.json             // extension's manifest

重要

开发计算机必须运行 最新版本的 Node ,以确保编写的代码与代理上的生产环境和最新的非预览版 azure-pipelines-task-lib兼容。 根据以下命令更新task.json文件:

"execution": {
   "Node20_1": {
     "target": "index.js"
   }
 }

1.创建自定义任务

buildandreleasetask 文件夹中执行此过程的每个部分。

注意

此示例演练将 Windows 与 PowerShell 配合使用。 我们对所有平台进行了通用化,但用于获取环境变量的语法不同。 如果使用 Mac 或 Linux,请将任何实例 $env:<var>=<val> 替换为 export <var>=<val>

创建任务基架

  1. 为任务创建文件夹结构,并安装所需的库和依赖项。

  2. 打开 PowerShell 命令窗口,转到文件夹 buildandreleasetask ,然后运行以下命令。

    npm init --yes
    

    npm initpackage.json创建文件。 添加了参数 --yes 以接受所有默认 npm init 选项。

    提示

    代理不会自动安装所需的模块,因为任务文件夹需要包含节点模块。 若要缓解此问题,请复制到 node_modules buildandreleasetask. 随着任务变大,很容易超过 VSIX 文件的大小限制(50MB)。 在复制节点文件夹之前,可能需要运行 npm install --productionnpm prune --production编写脚本来生成和打包所有内容。

  3. 添加到 azure-pipelines-task-lib 库。

    npm install azure-pipelines-task-lib --save
    
  4. 确保为外部依赖项安装 TypeScript 键入。

    npm install @types/node --save-dev
    npm install @types/q --save-dev
    
  5. 创建文件 .gitignore 并向其添加node_modules。 生成过程应执行一个和一个npm installtypings install操作,以便每次生成node_modules,无需签入。

    echo node_modules > .gitignore
    
  6. 将 Mocha 安装为开发依赖项。

    npm install mocha --save-dev -g
    npm install sync-request --save-dev
    npm install @types/mocha --save-dev
    
  7. 选择 TypeScript 版本 2.3.4 或 4.6.3。

    npm install typescript@4.6.3 -g --save-dev
    

    注意

    请确保在开发环境中使用 npm 全局安装 TypeScript,以便 tsc 命令可用。 如果跳过此步骤,则默认情况下使用 TypeScript 版本 2.3.4,并且仍需全局安装包,才能让 tsc 命令可用。

  8. 创建 tsconfig.json 编译器选项。 此文件可确保 TypeScript 文件编译为 JavaScript 文件。

    tsc --init --target es2022
    

创建任务

现在基架已完成,我们可以创建自定义任务。

  1. buildandreleasetask文件夹中创建task.json文件。 该文件 task.json 描述生成/发布任务,以及生成/发布系统用于向用户呈现配置选项以及知道在生成/发布时要执行的脚本。

  2. 复制以下代码,并将其替换为 {{placeholders}} 任务的信息。 最重要的占位符是 taskguid,它必须是唯一的。

    {
     "$schema": "https://raw.githubusercontent.com/Microsoft/azure-pipelines-task-lib/master/tasks.schema.json",
     "id": "{{taskguid}}",
     "name": "{{taskname}}",
     "friendlyName": "{{taskfriendlyname}}",
     "description": "{{taskdescription}}",
     "helpMarkDown": "",
     "category": "Utility",
     "author": "{{taskauthor}}",
     "version": {
         "Major": 0,
         "Minor": 1,
         "Patch": 0
     },
     "instanceNameFormat": "Echo $(samplestring)",
     "inputs": [
         {
             "name": "samplestring",
             "type": "string",
             "label": "Sample String",
             "defaultValue": "",
             "required": true,
             "helpMarkDown": "A sample string"
         }
     ],
     "execution": {
         "Node20_1": {
             "target": "index.js"
         }
     }
     }
    
  3. index.ts使用以下代码作为引用创建文件。 此代码在调用任务时运行。

    import tl = require('azure-pipelines-task-lib/task');
    
     async function run() {
         try {
             const inputString: string | undefined = tl.getInput('samplestring', true);
             if (inputString == 'bad') {
                 tl.setResult(tl.TaskResult.Failed, 'Bad input was given');
                 return;
             }
             console.log('Hello', inputString);
         }
         catch (err:any) {
             tl.setResult(tl.TaskResult.Failed, err.message);
         }
     }
    
     run();
    
  4. buildandreleasetask文件夹中输入“tsc”以从index.ts中编译index.js文件。

task.json组件

请参阅文件的一些组件的 task.json 以下说明。

properties 说明
id 任务的唯一 GUID。
name 不带空格的名称。
friendlyName 描述性名称(允许空格)。
description 任务用途的详细说明。
author 描述开发生成或发布任务的实体的简短字符串,例如:“Microsoft Corporation”。
instanceNameFormat 任务在生成/发布步骤列表中显示的方式。 可以使用 $(variablename)来使用变量值
groups 描述 UI 中任务属性的逻辑分组。
inputs 生成或发布任务运行时要使用的输入。 此任务需要具有名称 samplestring 的输入。
execution 此任务的执行选项,包括脚本。
restrictions 应用于有关 GitHub Codespaces 命令 任务可以调用的任务的限制,变量任务可以设置。 建议为新任务指定限制模式。

注意

在 PowerShell 中使用以下命令创建一个 id

(New-Guid).Guid

有关详细信息,请参阅 生成/发布任务参考

运行任务

使用 node index.js PowerShell 运行任务。

在以下示例中,任务失败,因为未提供输入(samplestring 是所需的输入)。

 node index.js
 ##vso[task.debug]agent.workFolder=undefined
 ##vso[task.debug]loading inputs and endpoints
 ##vso[task.debug]loaded 0
 ##vso[task.debug]task result: Failed
 ##vso[task.issue type=error;]Input required: samplestring
 ##vso[task.complete result=Failed;]Input required: samplestring

作为修补程序,我们可以设置 samplestring 输入并再次运行任务。

$env:INPUT_SAMPLESTRING="Human"
node index.js
##vso[task.debug]agent.workFolder=undefined
##vso[task.debug]loading inputs and endpoints
##vso[task.debug]loading INPUT_SAMPLESTRING
##vso[task.debug]loaded 1
##vso[task.debug]Agent.ProxyUrl=undefined
##vso[task.debug]Agent.CAInfo=undefined
##vso[task.debug]Agent.ClientCert=undefined
##vso[task.debug]Agent.SkipCertValidation=undefined
##vso[task.debug]samplestring=Human
Hello Human

这次,任务成功,因为 samplestring 已提供,并且它正确输出了“Hello Human!”

提示

有关各种任务运行程序以及如何在task.json中包含最新节点版本的信息,请参阅 Azure Pipelines 任务作者的节点运行程序更新指南。

2.对任务脚本进行单元测试

执行单元测试以快速测试任务脚本,而不是它调用的外部工具。 测试成功路径和失败路径的各个方面。

  1. 安装测试工具。 在此过程中,我们使用 Mocha 作为测试驱动程序。

    npm install mocha --save-dev -g
    npm install sync-request --save-dev
    npm install @types/mocha --save-dev
    
  2. tests创建包含以下_suite.ts内容的文件的文件夹:

    import * as path from 'path';
    import * as assert from 'assert';
    import * as ttm from 'azure-pipelines-task-lib/mock-test';
    
    describe('Sample task tests', function () {
    
        before( function() {
    
        });
    
        after(() => {
    
        });
    
        it('should succeed with simple inputs', function(done: Mocha.Done) {
            // Add success test here
        });
    
        it('it should fail if tool returns 1', function(done: Mocha.Done) {
            // Add failure test here
        });    
    });
    

    提示

    测试文件夹应位于 buildandreleasetask 文件夹中。 如果收到同步请求错误,可以通过使用命令 npm i --save-dev sync-request将 sync-request 添加到 buildandreleasetask 文件夹来解决此问题。

  3. success.ts在测试目录中创建包含以下内容的文件。 此文件创建模拟运行任务并模拟对外部方法的所有调用。

    import ma = require('azure-pipelines-task-lib/mock-answer');
    import tmrm = require('azure-pipelines-task-lib/mock-run');
    import path = require('path');
    
    let taskPath = path.join(__dirname, '..', 'index.js');
    let tmr: tmrm.TaskMockRunner = new tmrm.TaskMockRunner(taskPath);
    
    tmr.setInput('samplestring', 'human');
    
    tmr.run();
    

    成功测试验证是否使用适当的输入,它成功且没有错误或警告,并返回正确的输出。

  4. 将以下示例成功测试添加到 _suite.ts 文件以运行任务模拟运行程序。

        it('should succeed with simple inputs', function(done: Mocha.Done) {
        this.timeout(1000);
    
        let tp: string = path.join(__dirname, 'success.js');
        let tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp);
    
        // tr.run(); //current, old function.
        tr.runAsync().then(() => {
            console.log(tr.succeeded);
            assert.equal(tr.succeeded, true, 'should have succeeded');
            assert.equal(tr.warningIssues.length, 0, "should have no warnings");
            assert.equal(tr.errorIssues.length, 0, "should have no errors");
            console.log(tr.stdout);
            assert.equal(tr.stdout.indexOf('Hello human') >= 0, true, "should display Hello human");
            done();
        }).catch((error) => {
            done(error); // Ensure the test case fails if there's an error
        });
    });
    
  5. 在测试目录中创建一个 failure.ts 文件作为任务模拟运行程序,其中包含以下内容:

    import ma = require('azure-pipelines-task-lib/mock-answer');
    import tmrm = require('azure-pipelines-task-lib/mock-run');
    import path = require('path');
    
    let taskPath = path.join(__dirname, '..', 'index.js');
    let tmr: tmrm.TaskMockRunner = new tmrm.TaskMockRunner(taskPath);
    
    tmr.setInput('samplestring', 'bad');
    
    tmr.run();
    

    失败测试验证当工具收到错误或不完整的输入时,它会以预期方式失败,并得到有用的输出。

  6. 将以下代码添加到 _suite.ts 文件以运行任务模拟运行程序。

    it('it should fail if tool returns 1', function(done: Mocha.Done) {
        this.timeout(1000);
    
        let tp = path.join(__dirname, 'failure.js');
        let tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp);
    
        tr.run();
        console.log(tr.succeeded);
        assert.equal(tr.succeeded, false, 'should have failed');
        assert.equal(tr.warningIssues.length, 0, "should have no warnings");
        assert.equal(tr.errorIssues.length, 1, "should have 1 error issue");
        assert.equal(tr.errorIssues[0], 'Bad input was given', 'error issue output');
        assert.equal(tr.stdout.indexOf('Hello bad'), -1, "Should not display Hello bad");
    
        done();
    });
    
  7. 运行测试。

    tsc
    mocha tests/_suite.js
    

    这两个测试都应通过。 如果要使用更详细的输出(在生成控制台中看到的内容)运行测试,请设置环境变量: TASK_TEST_TRACE=1

    $env:TASK_TEST_TRACE=1
    

3.创建扩展清单文件

扩展清单包含有关扩展的所有信息。 它包括指向文件的链接,包括任务文件夹和图像文件夹。 确保已创建包含extension-icon.png的图像文件夹。 以下示例是包含生成或发布任务的扩展清单。

复制以下.json代码,并将其另存为 vss-extension.json 目录中的文件 home

请勿在 buildandreleasetask 文件夹中创建此文件。

{
    "manifestVersion": 1,
    "id": "build-release-task",
    "name": "Fabrikam Build and Release Tools",
    "version": "0.0.1",
    "publisher": "fabrikam",
    "targets": [
        {
            "id": "Microsoft.VisualStudio.Services"
        }
    ],    
    "description": "Tools for building/releasing with Fabrikam. Includes one build/release task.",
    "categories": [
        "Azure Pipelines"
    ],
    "icons": {
        "default": "images/extension-icon.png"        
    },
    "files": [
        {
            "path": "buildandreleasetask"
        }
    ],
    "contributions": [
        {
            "id": "custom-build-release-task",
            "type": "ms.vss-distributed-task.task",
            "targets": [
                "ms.vss-distributed-task.tasks"
            ],
            "properties": {
                "name": "buildandreleasetask"
            }
        }
    ]
}

注意

发布者更改为发布者 名称。 有关详细信息,请参阅 “创建发布者”。

发布内容

properties 说明
id 贡献的标识符。 在扩展中必须是唯一的。 不需要与生成或发布任务的名称匹配。 通常,生成或发布任务名称位于参与的 ID 中。
type 贡献的类型。 应为 ms.vss-distributed-task.task
targets 此贡献的“目标”贡献。 应为 ms.vss-distributed-task.tasks
properties.name 任务的名称。 此名称必须与相应的自包含生成或发布管道任务的文件夹名称匹配。

文件

属性 说明
path 相对于 home 目录的文件或文件夹的路径。

注意

有关扩展清单文件(例如其属性及其用途)的详细信息,请参阅 扩展清单参考

4.打包扩展

将所有文件打包在一起,将扩展引入 Visual Studio 市场。 所有扩展都打包为 VSIX 2.0 兼容的 .vsix 文件。 Microsoft提供了用于打包扩展的跨平台命令行接口(CLI)。

获取 tfx-cli 后,转到扩展的主目录,并运行以下命令:

tfx extension create --manifest-globs vss-extension.json

注意

每次更新时,都必须递增扩展或集成版本。 更新现有扩展时,请更新清单中的版本或传递 --rev-version 命令行开关。 这会递增 扩展的修补程序 版本号,并将新版本保存到清单。 必须同时更新任务版本和扩展版本才能进行更新。 tfx extension create --manifest-globs vss-extension.json --rev-version 仅更新扩展版本,而不是任务版本。 有关详细信息,请参阅 GitHub 中的生成任务。

打包的扩展名位于 .vsix 文件中后,即可将扩展发布到市场。

5.发布扩展

若要发布扩展,请先创建发布者,然后上传扩展,最后共享该扩展。

创建发布者

所有扩展(包括 Microsoft 的扩展)都标识为由发布者提供。 如果还没有现有发布者的成员,请创建一个。

  1. 登录到 Visual Studio Marketplace 发布门户
  2. 如果还没有现有发布者的成员,系统会提示你创建发布者。 如果未提示创建发布者,请向下滚动到页面底部,然后选择“相关网站下的“发布扩展”。
    • 为发布者指定标识符,例如: mycompany-myteam
      • 此标识符用作扩展清单文件中属性的值 publisher
    • 为发布者指定显示名称,例如: My Team
  3. 查看市场发布者协议,然后选择“创建”。

你的发布者已定义。 在将来的版本中,可以授予查看和管理发布者扩展的权限。 在通用发布者下发布扩展更容易且更安全,无需跨用户共享一组凭据。

上传扩展

找到“上传新扩展”按钮,转到打包的 .vsix 文件,然后选择“上传”。

  1. 还可以使用 tfx extension publish 命令(CLI)通过命令行接口(CLI)上传扩展,而不是 tfx extension create 在一个步骤中打包和发布扩展。 可以选择在 --share-with 扩展发布后与一个或多个帐户共享扩展。

    tfx extension publish --manifest-globs your-manifest.json --share-with yourOrganization
    
  2. 创建个人访问令牌(PAT)。

    • 选择“市场(发布)”范围。 此范围将令牌限制为仅能够将扩展发布到市场。

共享扩展

上传扩展后,它位于市场中,但没有人可以看到它。 与组织共享它,以便你可以安装和测试它。

右键单击扩展并选择“共享,然后输入组织信息。 也可以与想要访问扩展的其他帐户共享它。

重要

必须验证发布者才能公开共享扩展。 有关详细信息,请参阅 包/发布/安装

在市场中共享扩展后,任何想要使用它的人都必须安装它。

6. 创建生成和发布管道以将扩展发布到市场

在 Azure DevOps 上创建生成和发布管道,以帮助维护市场上的自定义任务。

先决条件

软件/工具

信息

Azure DevOps 项目

Azure DevOps 扩展任务扩展

管道库变量组

创建管道库变量组以保存管道使用的变量。 有关详细信息,请参阅 “添加和使用变量组”。 可以从 Azure DevOps 库选项卡或通过 CLI 生成变量组。 在管道中使用此组中的变量 。 此外,在变量组中声明以下变量:

  • publisherId:市场发布者的 ID
  • extensionId:扩展的 ID,如vss-extension.json文件中声明的那样
  • extensionName:扩展的名称,如vss-extension.json文件中声明的那样
  • artifactName:为 VSIX 文件创建的项目的名称

服务连接

创建新的市场服务连接并为所有管道授予访问权限。

YAML 管道

使用以下示例通过 YAML 创建新管道。 有关详细信息,请参阅 创建第一个管道YAML 架构

trigger: 
- main
pool:
vmImage: "ubuntu-latest"
variables:
- group: variable-group # Rename to whatever you named your variable group in the prerequisite stage of step 6
stages:
- stage: Run_and_publish_unit_tests
jobs:
- job:
steps:
- task: TfxInstaller@4
inputs:
version: "v0.x"
- task: Npm@1
inputs:
command: 'install'
workingDir: '/TaskDirectory' # Update to the name of the directory of your task
- task: Bash@3
displayName: Compile Javascript
inputs:
targetType: "inline"
script: |
cd TaskDirectory # Update to the name of the directory of your task
tsc
- task: Npm@1
inputs:
command: 'custom'
workingDir: '/TestsDirectory' # Update to the name of the directory of your task's tests
customCommand: 'testScript' # See the definition in the explanation section below - it may be called test
- task: PublishTestResults@2
inputs:
testResultsFormat: 'JUnit'
testResultsFiles: '**/ResultsFile.xml'
- stage: Package_extension_and_publish_build_artifacts
jobs:
- job:
steps:
- task: TfxInstaller@4
inputs:
version: "0.x"
- task: Npm@1
inputs:
command: 'install'
workingDir: '/TaskDirectory' # Update to the name of the directory of your task
- task: Bash@3
displayName: Compile Javascript
inputs:
targetType: "inline"
script: |
cd TaskDirectory # Update to the name of the directory of your task
tsc
- task: QueryAzureDevOpsExtensionVersion@4
name: QueryVersion
inputs:
connectTo: 'VsTeam'
connectedServiceName: 'ServiceConnection' # Change to whatever you named the service connection
publisherId: '$(PublisherID)'
extensionId: '$(ExtensionID)'
versionAction: 'Patch'
- task: PackageAzureDevOpsExtension@4
inputs:
rootFolder: '$(System.DefaultWorkingDirectory)'
publisherId: '$(PublisherID)'
extensionId: '$(ExtensionID)'
extensionName: '$(ExtensionName)'
extensionVersion: '$(QueryVersion.Extension.Version)'
updateTasksVersion: true
updateTasksVersionType: 'patch'
extensionVisibility: 'private' # Change to public if you're publishing to the marketplace
extensionPricing: 'free'
- task: CopyFiles@2
displayName: "Copy Files to: $(Build.ArtifactStagingDirectory)"
inputs:
Contents: "**/*.vsix"
TargetFolder: "$(Build.ArtifactStagingDirectory)"
- task: PublishBuildArtifacts@1
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
ArtifactName: '$(ArtifactName)'
publishLocation: 'Container'
- stage: Download_build_artifacts_and_publish_the_extension
jobs:
- job:
steps:
- task: TfxInstaller@4
inputs:
version: "v0.x"
- task: DownloadBuildArtifacts@0
inputs:
buildType: "current"
downloadType: "single"
artifactName: "$(ArtifactName)"
downloadPath: "$(System.DefaultWorkingDirectory)"
- task: PublishAzureDevOpsExtension@4
inputs:
connectTo: 'VsTeam'
connectedServiceName: 'ServiceConnection' # Change to whatever you named the service connection
fileType: 'vsix'
vsixFile: '$(PublisherID).$(ExtensionName)/$(PublisherID)..vsix'
publisherId: '$(PublisherID)'
extensionId: '$(ExtensionID)'
extensionName: '$(ExtensionName)'
updateTasksVersion: false
extensionVisibility: 'private' # Change to public if you're publishing to the marketplace
extensionPricing: 'free'

有关详细信息,请参阅 指定触发管道的事件。

注意

每个作业都使用新的用户代理,并要求安装依赖项。

管道阶段

以下部分可帮助你了解管道阶段的工作原理。

阶段 1:运行和发布单元测试

此阶段运行单元测试并将测试结果发布到 Azure DevOps。

若要运行单元测试,请将自定义脚本添加到package.json文件,如以下示例所示。

"scripts": {
    "testScript": "mocha ./TestFile --reporter xunit --reporter-option output=ResultsFile.xml"
},
  1. 添加“将 Node CLI 用于 Azure DevOps(tfx-cli)”,将 tfx-cli 安装到生成代理。

  2. 使用“install”命令添加“npm”任务,并将文件夹与package.json文件为目标。

  3. 添加“Bash”任务以将 TypeScript 编译为 JavaScript。

  4. 使用“custom”命令添加“npm”任务,以包含单元测试的文件夹为目标,并将输入作为命令添加 testScript 。 使用以下输入:

    • 命令:自定义
    • 包含package.json的工作文件夹:/TestsDirectory
    • 命令和参数: testScript
  5. 添加“发布测试结果”任务。 如果使用 Mocha XUnit 记者,请确保结果格式为“JUnit”而不是“XUnit”。将搜索文件夹设置为根目录。 使用以下输入:

    • 测试结果格式:JUnit
    • 测试结果文件:**/ResultsFile.xml
    • 搜索文件夹: $(System.DefaultWorkingDirectory)

    发布测试结果后,“测试”选项卡下的输出应如以下示例所示。

    测试结果示例的屏幕截图。

阶段 2:打包扩展并发布生成项目

  1. 添加“将 Node CLI 用于 Azure DevOps(tfx-cli)”,将 tfx-cli 安装到生成代理。

  2. 使用“install”命令添加“npm”任务,并将文件夹与package.json文件为目标。

  3. 添加“Bash”任务以将 TypeScript 编译为 JavaScript。

  4. 添加“查询扩展版本”任务以查询现有扩展版本。 使用以下输入:

    • 连接到:Visual Studio Marketplace
    • Visual Studio Marketplace (服务连接):服务连接
    • 发布者 ID:Visual Studio Marketplace 发布者的 ID
    • 扩展 ID:vss-extension.json文件中扩展的 ID
    • 增加版本:修补程序
    • 输出变量:Task.Extension.Version
  5. 添加“包扩展”任务,以基于清单 Json 打包扩展。 使用以下输入:

    • 根清单文件夹:指向包含清单文件的根目录。 例如,$(System.DefaultWorkingDirectory)是根目录
    • 清单文件(s): vss-extension.json
    • 发布者 ID:Visual Studio Marketplace 发布者的 ID
    • 扩展 ID:vss-extension.json文件中扩展的 ID
    • 扩展名:vss-extension.json 文件中扩展名的名称
    • 扩展版本:$(Task.Extension.Version)
    • 替代任务版本:已选中(true)
    • 替代类型:仅替换修补程序(1.0.r)
    • 扩展可见性:如果扩展仍在开发中,请将该值设置为私有。 若要将扩展发布到公共,请将值设置为公共
  6. 添加“复制文件”任务以复制已发布的文件。 使用以下输入:

    • 内容:要复制的所有文件以将其发布为项目
    • 目标文件夹:文件复制到的文件夹
      • 例如:$(Build.ArtifactStagingDirectory)
  7. 添加“发布生成项目”以发布项目以供其他作业或管道使用。 使用以下输入:

    • 发布路径:包含要发布的文件的文件夹的路径
      • 例如:$(Build.ArtifactStagingDirectory)
    • 项目名称:为项目提供的名称
    • 项目发布位置:选择“Azure Pipelines”,以便在将来的作业中使用项目

阶段 3:下载生成项目并发布扩展

  1. 添加“将 Node CLI 用于 Azure DevOps(tfx-cli)”,将 tfx-cli 安装到生成代理。

  2. 添加“下载生成项目”任务,将项目下载到新作业。 使用以下输入:

    • 下载生成的项目:如果要从同一管道在新作业上下载项目,请选择“当前生成”。如果要在新管道上下载,请选择“特定生成”。
    • 下载类型:选择“特定项目”以下载已发布的所有文件。
    • 项目名称:已发布的项目名称。
    • 目标目录:应下载文件的文件夹。
  3. 需要的最后一个任务是“发布扩展”任务。 使用以下输入:

    • 连接到:Visual Studio Marketplace
    • Visual Studio Marketplace 连接:ServiceConnection
    • 输入文件类型:VSIX 文件
    • VSIX 文件:/Publisher.*.vsix
    • 发布者 ID:Visual Studio Marketplace 发布者的 ID
    • 扩展 ID:vss-extension.json文件中扩展的 ID
    • 扩展名:vss-extension.json 文件中扩展名的名称
    • 扩展可见性:专用或公共

可选:安装和测试扩展

只需执行几个步骤即可安装与你共享的扩展:

  1. 从组织控制面板(https://dev.azure.com/{organization}/_admin)转到项目集合管理页面。
  2. 在“扩展”选项卡中,在“与我共享的扩展”组中找到扩展,然后选择扩展链接。
  3. 安装扩展。

如果看不到“ 扩展 ”选项卡,请确保位于控制面板(项目集合级别的管理页), https://dev.azure.com/{organization}/_admin而不是项目的管理页。

如果未看到“ 扩展 ”选项卡,则不会为组织启用扩展。 可以通过加入 Visual Studio 合作伙伴计划来提前访问扩展功能。

若要打包 Azure DevOps Extensions 并将其发布到 Visual Studio Marketplace,可以下载 Azure DevOps 扩展任务

常见问题

请参阅以下常见问题(常见问题解答),了解如何在 Azure DevOps 的扩展中添加自定义生成或发布任务。

问:如何限制任务的 Azure Pipelines 命令使用情况?

可以限制按任务设置的 Azure Pipelines 命令使用情况和变量。 此操作可用于防止对任务执行的自定义脚本的变量/vso 命令的无限制访问。 建议为新任务设置它。 若要应用,可能需要将以下语句添加到task.json文件:

  "restrictions": {
    "commands": {
      "mode": "restricted"
    },
    "settableVariables": {
      "allowed": ["variable1", "test*"]
    }
}

如果 restrictedmode 指定了值 - 则只能由任务执行以下命令:

  • logdetail
  • logissue
  • complete
  • setprogress
  • setsecret
  • setvariable
  • debug
  • settaskvariable
  • prependpath
  • publish

这些 settableVariables 限制允许传入变量的允许列表,这些变量由 setvariableprependpath 命令设置。 它还允许基本正则表达式。 例如,如果允许列表是:['abc', 'test*']、设置abctesttest1作为具有任何值的变量,或者将其追加到路径前会成功,但如果尝试设置变量代理,则会发出警告。 空列表意味着任务不会更改任何变量。

settableVariables如果省略或commands密钥,则不会应用相关限制。

限制功能可从 2.182.1 代理版本获取。

问:如何由任务处理取消信号?

答:管道代理向相关子进程发送 SIGINTSIGTERM 发出信号。 任务库中没有要处理的显式手段。 有关详细信息,请参阅 代理作业取消

问:如何从项目集合中删除任务?

答:不支持自动删除任务。 自动删除不安全,会中断已使用此类任务的现有管道。 但是,可以将任务标记为已弃用。 为此, 请颠簸任务版本 并将 任务标记为已弃用

问:如何将自定义任务升级到最新的节点?

答:建议升级到 最新的 Node 版本。 有关示例信息,请参阅 将任务升级到 Node 20

由于Microsoft托管代理和各种 Azure DevOps Server 版本具有不同的生命周期,因此可以安装不同的节点运行程序版本,具体取决于任务正在运行的位置。 为了能够在具有不同节点运行程序的代理上运行相同的任务, task.json 文件可以包含多个执行部分。 在以下示例中,包含 Node 20 运行程序的 Azure Pipeline 代理默认会选择它,并且不会回退到 Node 10 实现的代理。

  "execution": {
    "Node10": {
      "target": "bash.js",
      "argumentFormat": ""
    },
    "Node20_1": {
      "target": "bash.js",
      "argumentFormat": ""
    }

升级任务:

  • 在各种 Node 运行程序版本上测试任务,以确保代码按预期方式运行。

  • 在任务的执行部分中,从NodeNode10更新到或Node20更新Node16

  • 若要支持较旧的服务器版本,应保留目标 Node/Node10 。 旧版 Azure DevOps Server 可能不包含最新的 Node 运行程序版本。

  • 可以选择共享目标中定义的入口点,或者将目标优化到使用的 Node 版本。

    "execution": {
       "Node10": {
         "target": "bash10.js",
         "argumentFormat": ""
    },
    "Node16": {
       "target": "bash16.js",
       "argumentFormat": ""
    },
    "Node20_1": {
       "target": "bash20.js",
       "argumentFormat": ""
    }
    

重要

在自定义任务上不添加对 Node 20 运行程序的支持将导致从pipelines-agent-*发布源安装的代理上任务失败。