Azure DevOps Services | Azure DevOps Server 2022 - Azure DevOps Server 2019
本指南逐步讲解如何创建、测试和发布自定义生成或发布任务作为 Azure DevOps 扩展。 使用自定义管道任务,可将 Azure DevOps 扩展到专为团队工作流定制的专用功能,从简单的实用工具扩展到与外部系统的复杂集成。
了解如何执行以下任务:
- 设置开发环境和项目结构
- 使用 TypeScript 和 Azure Pipelines 任务库创建任务逻辑
- 使用模拟框架实现全面的单元测试
- 打包扩展以供分发
- 发布到 Visual Studio 市场
- 为扩展维护设置自动化 CI/CD 管道
有关 Azure Pipelines 的详细信息,请参阅 什么是 Azure Pipelines?
注意
本文介绍基于代理的扩展中的代理任务。 有关服务器任务和基于服务器的扩展的信息,请参阅 服务器任务创作。
先决条件
在开始之前,请确保满足以下要求:
组件 | 要求 | 说明 |
---|---|---|
Azure DevOps 组织 | 必选 | 如果没有组织,请创建组织 |
文本编辑器 | 建议 | 用于 IntelliSense 和调试支持的 Visual Studio Code |
Node.js | 必选 | 安装 最新版本 (建议Node.js 20 或更高版本) |
TypeScript 编译器 | 必选 | 安装 最新版本 (版本 4.6.3 或更高版本) |
Azure DevOps CLI (tfx-cli) | 必选 | 安装到 npm i -g tfx-cli 包扩展 |
Azure DevOps 扩展 SDK | 必选 | 安装 azure-devops-extension-sdk 包 |
测试框架 | 必选 | Mocha 用于单元测试(在安装期间安装) |
项目结构
home
为项目创建目录。 完成本教程后,扩展应具有以下结构:
|--- README.md
|--- images
|--- extension-icon.png
|--- buildandreleasetask // Task scripts location
|--- task.json // Task definition
|--- index.ts // Main task logic
|--- package.json // Node.js dependencies
|--- tests/ // Unit tests
|--- _suite.ts
|--- success.ts
|--- failure.ts
|--- vss-extension.json // Extension manifest
重要
开发计算机必须运行 最新版本的 Node.js ,以确保与生产环境的兼容性。
task.json
更新文件以使用 Node 20:
"execution": {
"Node20_1": {
"target": "index.js"
}
}
1.创建自定义任务
本部分将指导你创建自定义任务的基本结构和实现。 此步骤中的所有文件都应在 buildandreleasetask
项目 home
目录内的文件夹中创建。
注意
本演练将 Windows 与 PowerShell 配合使用。 这些步骤适用于所有平台,但环境变量语法不同。 在 Mac 或 Linux 上,替换为 $env:<var>=<val>
export <var>=<val>
。
设置任务基架
创建基本项目结构并安装所需的依赖项:
若要初始化 Node.js 项目,请打开 PowerShell,转到文件夹
buildandreleasetask
,然后运行:npm init --yes
该文件
package.json
使用默认设置创建。 该--yes
标志会自动接受所有默认选项。提示
Azure Pipelines 代理要求任务文件夹包含节点模块。 复制到
node_modules
文件夹buildandreleasetask
。 若要管理 VSIX 文件大小(50 MB 限制),请考虑运行npm install --production
或在npm prune --production
打包之前。安装 Azure Pipelines 任务库:
npm install azure-pipelines-task-lib --save
安装 TypeScript 类型定义:
npm install @types/node --save-dev npm install @types/q --save-dev
设置版本控制排除项
echo node_modules > .gitignore
每次生成过程都应运行
npm install
以重新生成node_modules。安装测试依赖项:
npm install mocha --save-dev -g npm install sync-request --save-dev npm install @types/mocha --save-dev
安装 TypeScript 编译器:
npm install typescript@4.6.3 -g --save-dev
注意
全局安装 TypeScript 以确保
tsc
命令可用。 如果没有它,则默认使用 TypeScript 2.3.4。配置 TypeScript 编译:
tsc --init --target es2022
该文件
tsconfig.json
使用 ES2022 目标设置创建。
实现任务逻辑
完成基架后,创建定义功能和元数据的核心任务文件:
创建任务定义文件:在
buildandreleasetask
文件夹中创建task.json
。 此文件介绍 Azure Pipelines 系统的任务、定义输入、执行设置和 UI 演示文稿。{ "$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" } } }
注意
替换为
{{placeholders}}
任务的实际信息。taskguid
必须独一无二。 使用 PowerShell 生成一个:(New-Guid).Guid
若要实现任务逻辑,请使用任务的主要功能创建
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();
将 TypeScript 编译为 JavaScript:
tsc
index.js
从 TypeScript 源创建该文件。
了解 task.json 组件
该文件 task.json
是任务定义的核心。 以下是关键属性:
属性 | 说明 | 示例: |
---|---|---|
id |
任务的唯一 GUID 标识符 | 使用 (New-Guid).Guid |
name |
不带空格的任务名称(在内部使用) | MyCustomTask |
friendlyName |
UI 中显示的显示名称 | My Custom Task |
description |
任务功能的详细说明 | Performs custom operations on files |
author |
发布者或作者名称 | My Company |
instanceNameFormat |
任务在管道步骤中的显示方式 | Process $(inputFile) |
inputs |
输入参数数组 | 请参阅以下输入类型 |
execution |
执行环境规范 |
Node20_1 、PowerShell3 等 |
restrictions |
命令和变量的安全限制 | 建议用于新任务 |
安全限制
对于生产任务,请添加安全限制以限制命令使用情况和变量访问:
"restrictions": {
"commands": {
"mode": "restricted"
},
"settableVariables": {
"allowed": ["variable1", "test*"]
}
}
受限模式 仅允许以下命令:
-
logdetail
、logissue
、complete
、setprogress
-
setsecret
、setvariable
、debug
、settaskvariable
-
prependpath
、publish
变量允许列表 控制可通过 setvariable
或 prependpath
设置哪些变量。 支持基本正则表达式模式。
注意
此功能需要 代理版本 2.182.1 或更高版本。
输入类型和示例
任务参数的常见输入类型:
"inputs": [
{
"name": "stringInput",
"type": "string",
"label": "Text Input",
"defaultValue": "",
"required": true,
"helpMarkDown": "Enter a text value"
},
{
"name": "boolInput",
"type": "boolean",
"label": "Enable Feature",
"defaultValue": "false",
"required": false
},
{
"name": "picklistInput",
"type": "pickList",
"label": "Select Option",
"options": {
"option1": "First Option",
"option2": "Second Option"
},
"defaultValue": "option1"
},
{
"name": "fileInput",
"type": "filePath",
"label": "Input File",
"required": true,
"helpMarkDown": "Path to the input file"
}
]
在本地测试任务
在打包之前,请测试任务以确保其正常工作:
缺少输入的测试(应失败):
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
使用有效输入进行测试(应成功):
$env:INPUT_SAMPLESTRING="World" 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]samplestring=World Hello World
测试错误处理:
$env:INPUT_SAMPLESTRING="bad" node index.js
此作应触发代码中的错误处理路径。
提示
有关任务运行程序和 Node.js 版本的信息,请参阅 Node 运行程序更新指南。
有关详细信息,请参阅 生成/发布任务参考。
2. 实现全面的单元测试
彻底测试任务可确保可靠性,并帮助在部署到生产管道之前捕获问题。
安装测试依赖项
安装所需的测试工具:
npm install mocha --save-dev -g
npm install sync-request --save-dev
npm install @types/mocha --save-dev
创建测试
在任务目录中创建包含
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() { // Setup before tests }); after(() => { // Cleanup after tests }); it('should succeed with simple inputs', function(done: Mocha.Done) { // Success test implementation }); it('should fail if tool returns 1', function(done: Mocha.Done) { // Failure test implementation }); });
提示
测试文件夹应位于任务文件夹中(例如
buildandreleasetask
)。 如果遇到同步请求错误,请在任务文件夹中安装它:npm i --save-dev sync-request
。在测试目录中创建
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); // Set valid input for success scenario tmr.setInput('samplestring', 'human'); tmr.run();
将成功测试添加到
_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.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 }); });
在测试目录中创建
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); // Set invalid input to trigger failure tmr.setInput('samplestring', 'bad'); tmr.run();
将失败测试添加到
_suite.ts
文件:it('should fail if tool returns 1', function(done: Mocha.Done) { this.timeout(1000); const tp = path.join(__dirname, 'failure.js'); const tr: ttm.MockTestRunner = new ttm.MockTestRunner(tp); tr.runAsync().then(() => { 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(); }); });
运行您的测试
执行测试套件:
# Compile TypeScript
tsc
# Run tests
mocha tests/_suite.js
这两个测试都应通过。 对于详细输出(类似于生成控制台输出),请设置跟踪环境变量:
$env:TASK_TEST_TRACE=1
mocha tests/_suite.js
测试覆盖率最佳做法
- 测试所有输入组合:有效输入、输入无效、缺少所需的输入
- 测试错误方案:网络故障、文件系统错误、权限问题
- 模拟外部依赖项:不要依赖单元测试中的外部服务
- 验证输出:检查控制台输出、任务结果和生成的项目
- 性能测试:考虑为处理大型文件的任务添加测试
安全最佳做法
- 输入验证:始终验证和清理输入
-
机密处理:用于
setSecret
敏感数据 - 命令限制:对生产任务实施命令限制
- 最小权限:仅请求必要的权限
- 常规更新:使依赖项和 Node.js 版本保持最新
在本地测试任务并实现全面的单元测试后,将其打包到 Azure DevOps 的扩展中。
安装打包工具
安装跨平台命令行接口(tfx-cli):
npm install -g tfx-cli
创建扩展清单
扩展清单 (vss-extension.json
) 包含有关扩展的所有信息,包括对任务文件夹和映像的引用。
使用文件创建图像文件夹
extension-icon.png
在扩展的根目录中创建
vss-extension.json
(不在任务文件夹中):{ "manifestVersion": 1, "id": "my-custom-tasks", "name": "My Custom Tasks", "version": "1.0.0", "publisher": "your-publisher-id", "targets": [ { "id": "Microsoft.VisualStudio.Services" } ], "description": "Custom build and release tasks for Azure DevOps", "categories": [ "Azure Pipelines" ], "icons": { "default": "images/extension-icon.png" }, "files": [ { "path": "MyCustomTask" } ], "contributions": [ { "id": "my-custom-task", "type": "ms.vss-distributed-task.task", "targets": [ "ms.vss-distributed-task.tasks" ], "properties": { "name": "MyCustomTask" } } ] }
关键清单属性
属性 | 说明 |
---|---|
publisher |
市场发布者标识符 |
contributions.id |
扩展内的唯一标识符 |
contributions.properties.name |
必须与任务文件夹名称匹配 |
files.path |
相对于清单的任务文件夹的路径 |
注意
将 发布者 值更改为发布者名称。 有关创建发布者的信息,请参阅 “创建发布者”。
打包扩展
将扩展名打包到 .vsix 文件中:
tfx extension create --manifest-globs vss-extension.json
版本管理
-
扩展版本:递增每个更新的版本
vss-extension.json
-
任务版本:递增每个任务更新的版本
task.json
-
自动递增:用于
--rev-version
自动递增修补程序版本
tfx extension create --manifest-globs vss-extension.json --rev-version
重要
必须更新任务版本和扩展版本,以便更改在 Azure DevOps 中生效。
版本控制策略
遵循任务更新的语义版本控制原则:
- 主要版本:对输入/输出的重大更改
- 次要版本:新功能,向后兼容
- 修补程序版本:仅 Bug 修复
更新过程:
- 更新
task.json
版本 - 更新
vss-extension.json
版本 - 在测试组织中全面测试
- 发布和监视问题
发布到 Visual Studio Marketplace
1.创建发布者
- 登录到 Visual Studio Marketplace 发布门户
- 如果系统提示,请创建新的发布服务器:
-
发布者标识符:在扩展清单中使用(例如)
mycompany-myteam
-
显示名称:市场中显示的公共名称(例如
My Team
)
-
发布者标识符:在扩展清单中使用(例如)
- 查看并接受 市场发布者协议
2.上传扩展
Web 接口方法:
- 选择 “上传新扩展”
- 选择打包
.vsix
的文件 - 选择“上传”
命令行方法:
tfx extension publish --manifest-globs vss-extension.json --share-with yourOrganization
3.共享扩展
- 在市场中右键单击扩展
- 选择共享
- 输入组织名称
- 根据需要添加更多组织
重要
必须验证发布者才能公开共享扩展。 有关详细信息,请参阅 包/发布/安装。
4.安装到组织
共享后,将扩展安装到 Azure DevOps 组织:
- 导航到 组织设置>扩展
- 浏览扩展
- 选择“ 免费获取 并安装”
3.打包并发布扩展
验证扩展
安装后,验证任务是否正常工作:
- 创建或编辑管道。
- 添加自定义任务:
- 在管道编辑器中选择 “添加任务 ”
- 按名称搜索自定义任务
- 将其添加到管道
- 配置任务参数:
- 设置所需的输入
- 配置可选设置
- 运行管道以测试功能
- 监视执行:
- 检查任务日志以正确执行
- 验证预期输出
- 确保没有错误或警告
4.使用 CI/CD 自动发布扩展
若要有效维护自定义任务,请创建用于处理测试、打包和发布的自动化生成和发布管道。
自动化的先决条件
- Azure DevOps 扩展任务:免费安装扩展
-
变量组:使用以下变量创建 管道库变量组 :
-
publisherId
:市场发布者 ID -
extensionId
:来自 vss-extension.json 的扩展 ID -
extensionName
:来自 vss-extension.json 的扩展名称 -
artifactName
:VSIX 项目的名称
-
- 服务连接:使用管道访问权限创建市场服务连接
完成 CI/CD 管道
创建一个 YAML 管道,其中包含用于测试、打包和发布的综合阶段:
trigger:
- main
pool:
vmImage: "ubuntu-latest"
variables:
- group: extension-variables # Your variable group name
stages:
- stage: Test_and_validate
displayName: 'Run Tests and Validate Code'
jobs:
- job: RunTests
displayName: 'Execute unit tests'
steps:
- task: TfxInstaller@4
displayName: 'Install TFX CLI'
inputs:
version: "v0.x"
- task: Npm@1
displayName: 'Install task dependencies'
inputs:
command: 'install'
workingDir: '/MyCustomTask' # Update to your task directory
- task: Bash@3
displayName: 'Compile TypeScript'
inputs:
targetType: "inline"
script: |
cd MyCustomTask # Update to your task directory
tsc
- task: Npm@1
displayName: 'Run unit tests'
inputs:
command: 'custom'
workingDir: '/MyCustomTask' # Update to your task directory
customCommand: 'test' # Ensure this script exists in package.json
- task: PublishTestResults@2
displayName: 'Publish test results'
inputs:
testResultsFormat: 'JUnit'
testResultsFiles: '**/test-results.xml'
searchFolder: '$(System.DefaultWorkingDirectory)'
- stage: Package_extension
displayName: 'Package Extension'
dependsOn: Test_and_validate
condition: succeeded()
jobs:
- job: PackageExtension
displayName: 'Create VSIX package'
steps:
- task: TfxInstaller@4
displayName: 'Install TFX CLI'
inputs:
version: "v0.x"
- task: Npm@1
displayName: 'Install dependencies'
inputs:
command: 'install'
workingDir: '/MyCustomTask'
- task: Bash@3
displayName: 'Compile TypeScript'
inputs:
targetType: "inline"
script: |
cd MyCustomTask
tsc
- task: QueryAzureDevOpsExtensionVersion@4
name: QueryVersion
displayName: 'Query current extension version'
inputs:
connectTo: 'VsTeam'
connectedServiceName: 'marketplace-connection'
publisherId: '$(publisherId)'
extensionId: '$(extensionId)'
versionAction: 'Patch'
- task: PackageAzureDevOpsExtension@4
displayName: 'Package extension'
inputs:
rootFolder: '$(System.DefaultWorkingDirectory)'
publisherId: '$(publisherId)'
extensionId: '$(extensionId)'
extensionName: '$(extensionName)'
extensionVersion: '$(QueryVersion.Extension.Version)'
updateTasksVersion: true
updateTasksVersionType: 'patch'
extensionVisibility: 'private'
extensionPricing: 'free'
- task: PublishBuildArtifacts@1
displayName: 'Publish VSIX artifact'
inputs:
PathtoPublish: '$(System.DefaultWorkingDirectory)/*.vsix'
ArtifactName: '$(artifactName)'
publishLocation: 'Container'
- stage: Publish_to_marketplace
displayName: 'Publish to Marketplace'
dependsOn: Package_extension
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
jobs:
- deployment: PublishExtension
displayName: 'Deploy to marketplace'
environment: 'marketplace-production'
strategy:
runOnce:
deploy:
steps:
- task: TfxInstaller@4
displayName: 'Install TFX CLI'
inputs:
version: "v0.x"
- task: PublishAzureDevOpsExtension@4
displayName: 'Publish to marketplace'
inputs:
connectTo: 'VsTeam'
connectedServiceName: 'marketplace-connection'
fileType: 'vsix'
vsixFile: '$(Pipeline.Workspace)/$(artifactName)/*.vsix'
publisherId: '$(publisherId)'
extensionId: '$(extensionId)'
extensionName: '$(extensionName)'
updateTasksVersion: false
extensionVisibility: 'private'
extensionPricing: 'free'
配置用于测试的 package.json
将测试脚本添加到:package.json
{
"scripts": {
"test": "mocha tests/_suite.js --reporter xunit --reporter-option output=test-results.xml",
"test-verbose": "cross-env TASK_TEST_TRACE=1 npm test"
}
}
管道阶段细分
阶段 1:测试和验证
- 目的:确保代码质量和功能
- 作:安装依赖项、编译 TypeScript、运行单元测试、发布结果
- 验证:所有测试都必须通过才能继续
阶段 2:包扩展
- 目的:创建可部署的 VSIX 包
- 作:查询当前版本、增量版本、包扩展、发布项目
- 版本控制:自动处理版本增量
阶段 3:发布到市场
- 目的:部署到 Visual Studio Marketplace
- 条件:仅在成功打包后在主分支上运行
- 环境:将部署环境用于审批入口
CI/CD 最佳做法
- 分支保护:仅从主/发布分支发布
- 环境入口:将部署环境用于生产版本
- 版本管理:自动执行版本增量以避免冲突
- 测试覆盖率:在打包之前确保全面的测试覆盖率
- 安全性:使用服务连接而不是硬编码凭据
- 监视:为失败的部署设置警报
对于经典生成管道,请按照以下步骤设置扩展打包和发布:
添加
Bash
任务以将 TypeScript 编译到 JavaScript 中。若要查询现有版本,请使用以下输入添加 查询扩展版本 任务:
- 连接到:Visual Studio Marketplace
- Visual Studio Marketplace(服务连接):服务连接
- 发布者 ID:Visual Studio Marketplace 发布者的 ID
- 扩展 ID:
vss-extension.json
文件中扩展的 ID - 版本升级:补丁
- 输出变量:
Task.Extension.Version
若要基于清单 Json 打包扩展,请使用以下输入添加 包扩展 任务:
- 根清单文件夹:指向包含清单文件的根目录。 例如,
$(System.DefaultWorkingDirectory)
是根目录。 - 清单文件:
vss-extension.json
- 发布者 ID:Visual Studio Marketplace 发布者的 ID
- 扩展 ID:
vss-extension.json
文件中扩展的 ID - 扩展名:
vss-extension.json
文件中扩展的名称 - 扩展版本:
$(Task.Extension.Version)
- 替代任务版本:已选中 (true)
- 替代类型:仅替换补丁 (1.0.r)
- 扩展可见性:如果扩展仍在开发中,请将该值设置为 私有。 若要将扩展发布到公共,请将值设置为 公共。
- 根清单文件夹:指向包含清单文件的根目录。 例如,
若要复制到已发布的文件,请使用以下输入添加 “复制文件 ”任务:
- 内容:所有要复制以便发布为工件的文件。
- 目标文件夹:文件复制到的文件夹
- 例如:
$(Build.ArtifactStagingDirectory)
- 例如:
添加发布生成项目以发布要在其他作业或管道中使用的项目。 使用以下输入:
- 发布路径:包含要发布的文件的文件夹的路径
- 例如:
$(Build.ArtifactStagingDirectory)
- 例如:
- 文物名称:分配给该文物的名称
- 工件发布路径:选择 Azure Pipelines 以便在后续作业中使用该工件。
- 发布路径:包含要发布的文件的文件夹的路径
阶段 3:下载生成产物并发布扩展程序
要将 tfx-cli 安装到生成代理上,请添加将 Node CLI 用于 Azure DevOps (tfx-cli)。
若要将项目下载到新作业,请使用以下输入添加 “下载生成项目 ”任务:
- 下载以下作业生成的工件:如果要在新作业中从同一管道下载工件,请选择当前生成。 如果要在新管道上下载,请选择特定生成
- 下载类型:选择 特定项目 以下载已发布的所有文件。
- 项目名称:已发布的项目名称
- 目标目录:应下载文件的文件夹
若要获取 发布扩展 任务,请使用以下输入:
- 连接到:Visual Studio Marketplace
- Visual Studio Marketplace 连接:ServiceConnection
- 输入文件类型:VSIX 文件
- VSIX 文件:
/Publisher.*.vsix
- 发布者 ID:Visual Studio Marketplace 发布者的 ID
- 扩展 ID:
vss-extension.json
文件中扩展的 ID - 扩展名:
vss-extension.json
文件中扩展的名称 - 扩展可见性:私有或公共
可选:安装和测试扩展
发布扩展后,需要在 Azure DevOps 组织中安装它。
将扩展安装到组织
在几个步骤中安装共享扩展:
转到 “组织”设置 ,然后选择“ 扩展”。
在“ 与我共享的扩展 ”部分找到扩展:
- 选择扩展链接
- 选择“ 免费获取” 或 “安装”
检查扩展是否显示在 “已安装 的扩展”列表中:
- 确认它在管道任务库中可用
注意
如果未看到“ 扩展 ”选项卡,请确保位于组织管理级别(https://dev.azure.com/{organization}/_admin
)而不是项目级别。
端到端测试
安装后,执行全面的测试:
创建测试管道:
- 将自定义任务添加到新管道
- 配置所有输入参数
- 使用各种输入组合进行测试
验证功能:
- 运行管道并监视执行
- 检查任务输出和日志
- 使用无效输入验证错误处理
测试性能:
- 使用大型输入文件进行测试(如果适用)
- 监视资源使用情况
- 验证超时行为
常见问题
问:如何处理任务取消?
答:管道代理向任务进程发送 SIGINT
并 SIGTERM
发出信号。 虽然 任务库 不提供显式取消处理,但任务可以实现信号处理程序。 有关详细信息,请参阅 代理作业取消。
问:如何从组织中删除任务?
答: 不支持自动删除 ,因为它会中断现有管道。 相反:
问:如何将任务升级到最新的 Node.js 版本?
答:升级到 最新的 Node 版本 ,以提高性能和安全性。 有关迁移指南,请参阅 将任务升级到 Node 20。
通过在以下项中包含多个执行部分task.json
来支持多个 Node 版本:
"execution": {
"Node20_1": {
"target": "index.js"
},
"Node10": {
"target": "index.js"
}
}
具有 Node 20 的代理使用首选版本,而较旧的代理则回退到 Node 10。
要升级你的任务,请执行以下操作:
若要确保代码按预期方式运行,请在各种 Node 运行程序版本上测试任务。
在任务的执行部分中,将
Node
或Node10
更新为Node16
或Node20
。若要支持较旧的服务器版本,应保留目标
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-*
发布源安装的代理上失败。