共用方式為


新增自定義管線任務擴充功能

Azure DevOps 服務 |Azure DevOps Server |Azure DevOps Server 2022 |Azure DevOps Server 2020

本指南會逐步引導您建立、測試及發佈自定義組建或發行工作作為 Azure DevOps 延伸模組。 自定義管線工作可讓您使用專為小組工作流程量身打造的特製化功能來擴充 Azure DevOps,從簡單的公用程式到與外部系統的複雜整合。

瞭解如何執行下列工作:

  • 設定開發環境和項目結構
  • 使用 TypeScript 和 Azure Pipelines 工作連結庫建立工作邏輯
  • 使用模擬架構實作完整的單元測試
  • 封裝延伸模組以進行散發
  • 發佈至 Visual Studio Marketplace
  • 設定延伸模組維護的自動化 CI/CD 管線

如需 Azure Pipelines 的詳細資訊,請參閱 什麼是 Azure Pipelines?

注意

本文涵蓋代理程式型擴充功能中的代理工作。 如需伺服器工作和伺服器型擴充功能的相關信息,請參閱 伺服器工作撰寫

必要條件

開始之前,請確定您已符合下列需求:

元件 要求 說明
Azure DevOps 組織 為必填項目 如果您沒有組織,請建立組織
文字編輯器 推薦 Visual Studio Code for IntelliSense 和偵錯支援
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 檔案以使用節點 20:

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

1.建立自定義工作

本節會引導您建立自定義工作的基本結構和實作。 此步驟中的所有檔案都應該在 buildandreleasetask 專案 home 目錄內的資料夾中建立。

注意

本逐步解說使用 Windows 與 PowerShell。 這些步驟適用於所有平臺,但環境變數語法不同。 在 Mac 或 Linux 上,將 取代 $env:<var>=<val>export <var>=<val>

設定工作 Scaffolding

建立基本項目結構並安裝必要的相依性:

  1. 若要初始化 Node.js 專案,請開啟 PowerShell,移至您的 buildandreleasetask 資料夾,然後執行:

    npm init --yes
    

    檔案 package.json 會以預設設定建立。 旗 --yes 標會自動接受所有預設選項。

    提示

    Azure Pipelines 代理程式預期工作資料夾必須包含節點模組。 複製到 node_modules 您的 buildandreleasetask 資料夾。 若要管理 VSIX 檔案大小(50 MB 限制),請考慮執行 npm install --productionnpm prune --production 封裝之前。

  2. 安裝 Azure Pipelines 工作連結庫:

    npm install azure-pipelines-task-lib --save
    
  3. 安裝 TypeScript 型態定義:

    npm install @types/node --save-dev
    npm install @types/q --save-dev
    
  4. 設定版本控制排除專案

    echo node_modules > .gitignore
    

    您的建置程式應該 npm install 每次執行以重建node_modules。

  5. 安裝測試相依性:

    npm install mocha --save-dev -g
    npm install sync-request --save-dev
    npm install @types/mocha --save-dev
    
  6. 安裝 TypeScript 編譯程式:

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

    注意

    全域安裝 TypeScript 以確保 tsc 命令可供使用。 如果沒有它,預設會使用 TypeScript 2.3.4。

  7. 設定 TypeScript 編譯:

    tsc --init --target es2022
    

    檔案 tsconfig.json 會以 ES2022 目標設定建立。

實作工作邏輯

完成 Scaffolding 後,建立定義功能和元數據的核心工作檔案:

  1. 建立工作定義檔:在 task.json 資料夾中建立buildandreleasetask。 此檔案會向 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

  2. 若要實作工作邏輯,請使用工作的主要功能來建立 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();
    
  3. 將 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_1PowerShell3 等。
restrictions 命令和變數的安全性限制 建議用於新工作

安全性限制

針對生產工作,新增安全性限制以限制命令使用方式和變數存取:

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

受限制模式 只允許下列命令:

  • logdetaillogissuecompletesetprogress
  • setsecretsetvariabledebugsettaskvariable
  • prependpathpublish

變數allowlist 控制可透過 setvariableprependpath設定哪些變數。 支援基本 regex 模式。

注意

此功能需要 代理程式 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"
    }
]

在本機測試您的工作

封裝之前,請先測試您的工作,以確保工作正常運作:

  1. 測試遺漏輸入 (應該失敗):

    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
    
  2. 使用有效輸入進行測試 (應該成功):

    $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
    
  3. 測試錯誤處理:

    $env:INPUT_SAMPLESTRING="bad"
    node index.js
    

    此動作應該會觸發程式代碼中的錯誤處理路徑。

    提示

    如需工作執行器和 Node.js 版本的相關信息,請參閱 節點執行器更新指引

如需詳細資訊,請參閱 建置/發行工作參考

2. 實作完整的單元測試

徹底測試您的工作可確保可靠性,並協助在部署到生產管線之前攔截問題。

安裝測試相依性

安裝必要的測試工具:

npm install mocha --save-dev -g
npm install sync-request --save-dev
npm install @types/mocha --save-dev

建立測試

  1. 在您的工作目錄中建立 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

  2. 在測試目錄中建立 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();
    
  3. 將成功測試新增至您的 _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
         });
     });
    
  4. 在測試目錄中建立 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();
    
  5. 將失敗測試新增至您的 _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) 包含擴充功能的所有資訊,包括工作資料夾和影像的參考。

  1. 使用 extension-icon.png 檔案建立 images 資料夾

  2. 在延伸模組的根目錄中建立 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

更新程式:

  1. 更新 task.json 版本
  2. 更新 vss-extension.json 版本
  3. 在測試組織中徹底測試
  4. 發佈和監視問題

發佈至 Visual Studio Marketplace

1.建立您的發行者

  1. 登入 Visual Studio Marketplace 發佈入口網站
  2. 如果出現提示,請建立新的發行者:
    • 發行者識別碼:在您的延伸模組指令清單中使用 (例如, mycompany-myteam
    • 顯示名稱:市集中顯示的公用名稱(例如) My Team
  3. 檢閱並接受 Marketplace 發行者合約

2.上傳您的延伸模組

Web 介面方法:

  1. 選取 [上傳新的擴充功能]
  2. 選擇已封裝的 .vsix 檔案
  3. 選取 [上傳]

命令列方法:

tfx extension publish --manifest-globs vss-extension.json --share-with yourOrganization

3.共用您的延伸模組

  1. 以滑鼠右鍵按兩下 Marketplace 中的延伸模組
  2. 選取共用
  3. 輸入您的組織名稱
  4. 視需要新增更多組織

重要

發行者必須經過驗證,才能公開分享擴充套件。 如需詳細資訊,請參閱 套件/發佈/安裝

4.安裝到您的組織

共享之後,請將擴充功能安裝到您的 Azure DevOps 組織:

  1. 流覽至 [組織設定>延伸模組]
  2. 流覽您的延伸模組
  3. 選取 [免費取得並安裝]

3.封裝併發佈您的延伸模組

確認您的擴充功能

安裝之後,請確認您的工作正常運作:

  1. 建立或編輯管線。
  2. 新增您的自訂工作:
    • 在管線編輯器中選取 [新增工作 ]
    • 依名稱搜尋您的自定義工作
    • 將它新增至管線
  3. 設定工作參數:
    • 設定必要的輸入
    • 設定選擇性設定
  4. 執行管線以測試功能
  5. 監視執行:
    • 檢查工作記錄檔中是否有適當的執行
    • 確認預期的輸出
    • 確定沒有任何錯誤或警告

4.使用 CI/CD 自動發佈延伸模組

若要有效地維護自定義工作,請建立自動化的建置和發行管線,以處理測試、封裝和發佈。

自動化的必要條件

  • Azure DevOps 擴充功能工作:免費安裝擴充功能
  • 變數群組:使用下列變數建立 管線連結庫變數群組
    • publisherId:您的市集發行者標識符
    • extensionId:來自 vss-extension.json 的擴充標識符
    • extensionName:vss-extension.json 的延伸模組名稱
    • artifactName:VSIX 成品的名稱
  • 服務連線:使用管線訪問許可權建立 Marketplace 服務連線

完成 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 的最佳做法

  • 分支保護:僅從主要/發行分支發佈
  • 環境閘道:針對生產版本使用部署環境
  • 版本管理:自動增加版本以避免衝突
  • 測試涵蓋範圍:在封裝之前確保完整的測試涵蓋範圍
  • 安全性:使用服務連線,而不是硬式編碼認證
  • 監視:設定失敗部署的警示

針對傳統組建管線,請遵循下列步驟來設定延伸模組封裝和發佈:

  1. 新增工作 Bash 以將 TypeScript 編譯至 JavaScript。

  2. 若要查詢現有的版本,請使用下列輸入新增 查詢延伸模組版本 工作:

    • 連線至:Visual Studio Marketplace
    • Visual Studio Marketplace(服務連線):服務連線
    • 發行者 ID:您在 Visual Studio Marketplace 上的發行者 ID
    • 延伸模組識別碼:在 vss-extension.json 檔案中的延伸模組識別碼
    • 版本升級:補丁
    • 輸出變數: Task.Extension.Version
  3. 若要根據 manifest JSON 封裝擴充功能,請使用下列輸入新增 封裝擴充功能 工作:

    • 根指令清單資料夾:指向包含指令清單檔的根目錄。 例如, $(System.DefaultWorkingDirectory) 是根目錄
    • 清單檔: vss-extension.json
    • 發行者 ID:您在 Visual Studio Marketplace 上的發行者 ID
    • 延伸模組識別碼:在 vss-extension.json 檔案中的延伸模組識別碼
    • 擴充套件名稱:在檔案中的 vss-extension.json 处指定的名稱
    • 擴充功能版本: $(Task.Extension.Version)
    • 覆蓋任務版本:已勾選(啟用)
    • 覆寫類型:僅替換補丁(1.0.r)
    • 延伸模組可見度:如果延伸模組仍在開發中,請將值設定為 私用。 若要將擴充功能發行至公用,請將值設定為 public
  4. 若要複製到已發佈的檔案,請使用下列輸入新增 複製檔案 工作:

    • 內容:要複製的所有檔案,以將它們發佈為成品
    • 目標資料夾:檔案複製到的資料夾
      • 例如:$(Build.ArtifactStagingDirectory)
  5. 新增 [發佈組建成品 ] 以發佈成品以供其他作業或管線使用。 使用以下輸入資料:

    • 發佈路徑:包含所發行檔案的資料夾路徑
      • 例如:$(Build.ArtifactStagingDirectory)
    • 文物名稱:指定給文物的名稱
    • 成品發布位置:選擇 Azure Pipelines 以便在未來的任務中使用此成品。

階段 3:下載組建成品併發佈延伸模組

  1. 若要將 tfx-cli 安裝到您的組建代理程式,請新增 使用 Azure DevOps 的 Node CLI (tfx-cli)

  2. 若要將工件下載到新的作業,請使用下列輸入新增 下載建置工件 任務:

    • 下載所產生的成品:如果您要從相同的管線下載新作業上的成品,請選取 [目前組建]。 如果您要在新管線上下載,請選取 [特定組建]
    • 下載類型:選擇 [特定成品 ] 以下載所有已發佈的檔案。
    • 成品名稱:已發佈的成品名稱
    • 目的地目錄:應該下載檔案的資料夾
  3. 若要取得 發佈擴充功能 工作,請使用下列輸入:

    • 連線至:Visual Studio Marketplace
    • Visual Studio Marketplace 連線:"ServiceConnection"
    • 輸入檔案類型:VSIX 檔案
    • VSIX 檔案: /Publisher.*.vsix
    • 發行者 ID:您在 Visual Studio Marketplace 上的發行者 ID
    • 延伸模組識別碼:在 vss-extension.json 檔案中的延伸模組識別碼
    • 擴充套件名稱:在檔案中的 vss-extension.json 处指定的名稱
    • 擴充功能可見性:私有或公開

選擇性:安裝和測試您的延伸模組

發佈擴充功能之後,它必須安裝在 Azure DevOps 組織中。

將擴充功能安裝到組織

在幾個步驟中安裝您的共享延伸模組:

  1. 移至 [組織設定 ],然後選取 [ 擴充功能]。

  2. 在 [ 與我共用的延伸模組 ] 區段中找出您的延伸模組:

    • 選取延伸模組連結
    • 選取 [免費取得] 或 [ 安裝]
  3. 檢查延伸模組是否 出現在已安裝的 擴充功能清單中:

    • 確認您的管線工作連結庫中有它可用

注意

如果您沒有看到 [ 延伸模組 ] 索引標籤,請確定您位於組織管理層級 (https://dev.azure.com/{organization}/_admin), 而不是在專案層級。

端對端測試

安裝之後,請執行完整的測試:

  1. 建立測試管線:

    • 將自訂工作新增至新的管線
    • 設定所有輸入參數
    • 使用各種輸入組合進行測試
  2. 驗證功能:

    • 執行管線並監視執行
    • 檢查工作輸出和記錄
    • 使用無效的輸入驗證錯誤處理
  3. 測試效能:

    • 使用大型輸入檔進行測試(如果適用)
    • 監視資源使用量
    • 驗證逾時行為

常見問題

問:如何處理工作取消?

答:管線代理程式會將 和 SIGINT 訊號傳送SIGTERM至工作進程。 雖然 工作連結庫 未提供明確的取消處理,但您的工作可以實作訊號處理程式。 如需詳細資訊,請參閱 代理程序作業取消

問:如何從我的組織移除工作?

答: 不支持自動刪除 ,因為它會中斷現有的管線。 相反:

  1. 取代工作將工作標示為已淘汰
  2. 版本管理顛簸工作版本
  3. 通訊:通知使用者淘汰時程表

問:如何將工作升級至最新的 Node.js 版本?

答:升級至 最新的節點版本 ,以提升效能和安全性。 如需移轉指引,請參閱 將工作升級至節點 20

支援多個節點版本 ,方法是在 中包含 task.json多個執行區段:

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

具有節點 20 的代理程式會使用慣用的版本,而較舊的代理程式則回復為節點 10。

若要升級您的任務:

  • 若要確保您的程式代碼如預期般運作,請在各種節點執行器版本上測試您的工作。

  • 在工作的執行區段中,從 NodeNode10 更新為 Node16Node20

  • 若要支援較舊的伺服器版本,您應該保留 Node/Node10 目標。 較舊的 Azure DevOps Server 版本可能未包含最新的節點執行器版本。

  • 您可以選擇共享目標中定義的進入點,或將目標優化至所使用的節點版本。

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

重要

如果您未將 Node 20 執行器的支援新增至您的自定義工作,它們就會在從 pipelines-agent-*發行摘要安裝的代理程式上失敗。