Поделиться через


Добавить расширение задачи для пользовательских конвейеров

Azure DevOps Services | 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 для IntelliSense и отладки
Node.js Обязательно Установите последнюю версию (рекомендуетсяNode.js 20 или более поздней версии)
Компилятор TypeScript Обязательно Установите последнюю версию (версия 4.6.3 или более поздняя)
Интерфейс командной строки Azure DevOps (tfx-cli) Обязательно Установка расширений пакетов с помощью npm i -g tfx-cli
Пакет SDK для расширения Azure DevOps Обязательно Установка пакета 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>.

Настройка шаблонов задач

Создайте базовую структуру проекта и установите необходимые зависимости:

  1. Чтобы инициализировать проект Node.js, откройте PowerShell, перейдите в buildandreleasetask папку и выполните следующую команду:

    npm init --yes
    

    Файл package.json создается с параметрами по умолчанию. Флаг --yes принимает все параметры по умолчанию автоматически.

    Совет

    Агенты Azure Pipelines ожидают, что папки задач будут включать модули узлов. Скопируйте node_modules в buildandreleasetask папку. Чтобы управлять размером файла VSIX (ограничение в 50 МБ), рассмотрите возможность выполнения npm install --production или npm 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 [email protected] -g --save-dev
    

    Примечание.

    Установите TypeScript глобально, чтобы убедиться, tsc что команда доступна. Без него TypeScript 2.3.4 используется по умолчанию.

  7. Настройка компиляции TypeScript:

    tsc --init --target es2022
    

    Файл tsconfig.json создается с параметрами целевого объекта ES2022.

Реализация логики задачи

После завершения формирования шаблонов создайте основные файлы задач, определяющие функциональные возможности и метаданные:

  1. Создайте файл определения задачи: создайте task.json в папке buildandreleasetask . Этот файл описывает задачу в системе Azure Pipelines, определяя входные данные, параметры выполнения и презентацию пользовательского интерфейса.

    {
     "$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 Отображаемое имя, отображаемое в пользовательском интерфейсе 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, , completesetprogress
  • setsecret, setvariable, , debugsettaskvariable
  • 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"
    }
]

Локальное тестирование задачи

Перед упаковкой проверьте задачу, чтобы убедиться, что она работает правильно:

  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 версиях см. в руководстве по обновлению runner узла.

Дополнительные сведения см. в справочнике по задаче сборки и выпуска.

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

  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 Идентификатор издателя Marketplace
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, необходимо обновить версию задачи и версию расширения.

Стратегия управления версиями

Следуйте принципам семантического управления версиями для обновлений задачи:

  • Основная версия: критические изменения входных и выходных данных
  • Дополнительная версия: новые функции, обратная совместимость
  • Версия исправления: исправление ошибок только

Процесс обновления:

  1. Обновление task.json версии
  2. Обновление vss-extension.json версии
  3. Тщательное тестирование в тестовой организации
  4. Публикация и мониторинг проблем

Публикация в Visual Studio Marketplace

1. Создание издателя

  1. Вход на портал публикации Visual Studio Marketplace
  2. При появлении запроса создайте нового издателя:
    • Идентификатор издателя: используется в манифесте расширения (например, mycompany-myteam)
    • Отображаемое имя: общедоступное имя, отображаемое в Marketplace (например, My Team)
  3. Просмотр и принятие соглашения издателя Marketplace

2. Отправка расширения

Метод веб-интерфейса:

  1. Выберите " Отправить новое расширение"
  2. Выбор упаковаемого .vsix файла
  3. Щелкните Отправить.

Метод командной строки:

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

3. Общий доступ к расширению

  1. Щелкните правой кнопкой мыши расширение в Marketplace
  2. Выберите Поделиться
  3. Введите имя организации
  4. Добавление дополнительных организаций по мере необходимости

Внимание

Издатели должны быть проверены для публичного распространения расширений. Дополнительные сведения см. в разделе "Package/Publish/Install".

4. Установка в организацию

После общего доступа установите расширение в организацию Azure DevOps:

  1. Перейдите красширениям>параметров организации
  2. Поиск расширения
  3. Выберите "Получить бесплатно " и установите

3. Упаковка и публикация расширения

Проверка расширения

После установки убедитесь, что задача работает правильно:

  1. Создание или изменение конвейера.
  2. Добавьте настраиваемую задачу:
    • Выбор задачи "Добавить" в редакторе конвейера
    • Поиск настраиваемой задачи по имени
    • Добавление его в конвейер
  3. Настройка параметров задачи:
    • Установка необходимых входных данных
    • Настройка необязательных параметров
  4. Запуск конвейера для тестирования функциональных возможностей
  5. Мониторинг выполнения:
    • Проверка журналов задач для правильного выполнения
    • Проверка ожидаемых выходных данных
    • Убедитесь, что ошибки или предупреждения отсутствуют

4. Автоматизация публикации расширений с помощью CI/CD

Чтобы эффективно поддерживать настраиваемую задачу, создайте автоматизированные конвейеры сборки и выпуска, обрабатывающие тестирование, упаковку и публикацию.

Предварительные требования для автоматизации

  • Задачи расширения Azure DevOps. Установка расширения бесплатно
  • Группа переменных: создайте группу переменных библиотеки конвейера с этими переменными:
    • publisherId: идентификатор издателя Marketplace
    • 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. Публикация в Marketplace

  • Назначение. Развертывание в Visual Studio Marketplace
  • Условия: только выполняется в основной ветви после успешной упаковки
  • Среда: использует среду развертывания для шлюзов утверждения

Лучшие практики для CI/CD

  • Защита ветви: только публикация из ветвей main/release
  • Шлюзы среды. Использование сред развертывания для рабочих выпусков
  • Управление версиями: автоматизация добавок версий для предотвращения конфликтов
  • Покрытие тестов: обеспечение комплексного покрытия тестов перед упаковкой
  • Безопасность: используйте подключения служб вместо жестко закодированных учетных данных
  • Мониторинг. Настройка оповещений для неудачных развертываний

Для классических конвейеров сборки выполните следующие действия, чтобы настроить упаковку расширений и публикацию:

  1. Добавьте задачу для компиляции Bash TypeScript в JavaScript.

  2. Чтобы запросить существующую версию, добавьте задачу расширения запроса с помощью следующих входных данных:

    • Подключение к: Visual Studio Marketplace
    • Visual Studio Marketplace (Сервисное соединение): Сервисное соединение
    • Идентификатор издателя: идентификатор издателя Visual Studio Marketplace
    • Идентификатор расширения: идентификатор расширения в vss-extension.json файле
    • Повышение версии: патч
    • Выходная переменная: Task.Extension.Version
  3. Чтобы упаковать расширения на основе json-манифеста, добавьте задачу Package Extension с помощью следующих входных данных:

    • Папка корневых манифестов: указывает на корневой каталог, содержащий файл манифеста. Например, $(System.DefaultWorkingDirectory) корневой каталог
    • Файл манифеста: vss-extension.json
    • Идентификатор издателя: идентификатор издателя Visual Studio Marketplace
    • Идентификатор расширения: идентификатор расширения в vss-extension.json файле
    • Имя расширения: Название вашего расширения в vss-extension.json файле
    • Версия расширения: $(Task.Extension.Version)
    • Переопределение версии задачи: отмечено (true)
    • Переопределение типа: только замена исправления (1.0.r)
    • Видимость расширения: если расширение по-прежнему находится в разработке, задайте для параметра private значение. Чтобы сделать расширение общедоступным, установите значение в public.
  4. Чтобы скопировать в опубликованные файлы, добавьте задачу копирования файлов с помощью следующих входных данных:

    • Содержимое: все файлы, которые необходимо копировать для публикации в качестве артефакта
    • Целевая папка: папка, в которую копируются файлы
      • Например: $(Build.ArtifactStagingDirectory)
  5. Добавьте Опубликовать артефакты сборки, чтобы разместить артефакты для использования в других заданиях и конвейерах. Используйте следующие входные данные:

    • Путь к публикации: путь к папке, содержащей опубликованные файлы
      • Например: $(Build.ArtifactStagingDirectory)
    • Имя артефакта: имя, заданное артефакту
    • Расположение публикации артефактов: выберите Azure Pipelines для использования артефакта в будущих заданиях

Этап 3. Скачивание артефактов сборки и публикация расширения

  1. Чтобы установить tfx-cli на ваш агент сборки, добавьте используйте Node CLI для Azure DevOps (tfx-cli).

  2. Чтобы скачать артефакты в новое задание, добавьте задачу download build artifacts с помощью следующих входных данных:

    • Скачайте артефакты, созданные: если вы скачиваете артефакт на новом задании из того же конвейера, выберите текущую сборку. Если вы скачиваете на новом конвейере, выберите конкретную сборку
    • Тип скачивания: выберите конкретный артефакт , чтобы скачать все опубликованные файлы.
    • Имя артефакта: имя опубликованного артефакта
    • Каталог назначения: папка, в которой должны быть скачаны файлы
  3. Чтобы получить задачу "Опубликовать расширение" , используйте следующие входные данные:

    • Подключение к: Visual Studio Marketplace
    • Подключение к Visual Studio Marketplace: ServiceConnection
    • Тип входного файла: VSIX-файл
    • VSIX-файл: /Publisher.*.vsix
    • Идентификатор издателя: идентификатор издателя Visual Studio Marketplace
    • Идентификатор расширения: идентификатор расширения в 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"
  }
}

Агенты с node 20 используют предпочтительную версию, а старые агенты возвращаются на Узел 10.

Чтобы обновить задачи, выполните следующие действия.

  • Чтобы убедиться, что код работает должным образом, протестируйте задачи в различных версиях runner node.

  • В разделе выполнения задачи обновите с Node или Node10 на Node16 или Node20.

  • Чтобы поддерживать более старые версии сервера, следует оставить целевой элемент Node/Node10. Более старые версии Azure DevOps Server могут не включать последнюю версию Node.js раннера.

  • Вы можете предоставить общий доступ к точке входа, определенной в целевом объекте, или иметь целевые объекты, оптимизированные для используемой версии узла.

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

Внимание

Если вы не добавите поддержку среды выполнения Node 20 в пользовательские задачи, они завершаются сбоем на агентах, установленных из канала релизов pipelines-agent-*.