Заметки консультанта

Шамрай Александр Владимирович

Создание собственной задачи сборки и релиза TFS для регистрации новых рабочих элементов на основе Node.JS

Posted by Shamrai Alexander на 14 февраля, 2019

Введение

На сегодняшний день доступно довольно много различных как стандартных, так и сторонних задач для шагов автоматизации сборки и развертывания релиза. Но иногда возникают потребности, которые не покрываются существующими решениями. Например, для релизов существуют некоторые встроенные возможности для утверждений развертывания и т.д., но иногда их не хватает. Т.е., если необходимо релиз «пропустить» через несколько отделов (тестирование, поддержка, безопасность), то требуется более чем один утверждающий. Это можно решить, например, динамическим созданием проверочных задач для соответствующих ответственных в зависимости от среды, где разворачивается релиз.

В рамках данного поста мы рассмотрим пример создания одного рабочего элемента для демонстрации возможностей. Данный пример может быть доработан для создания группы связанных задач.

Исходный код решения

Полный пример исходного кода решения находится здесь: https://github.com/ashamrai/AzureDevOpsExtensions/tree/master/CustomBuildTask

Решение подготовлено с помощью Visual Studio Code.

Предварительные настройки

В качестве подготовки рекомендуется выполнить следующие шаги:

  1. Развернуть пакет TFS Cross Platform Command Line Interface через команду npm i -g tfx-cli.
  2. Создать каталог, в котором будет находится все решение (Каталог решения).
  3. Создать каталог, в котором будет находится исходный код для создания рабочего элемента (Каталог исходного кода).
  4. Перейти в каталог исходного кода и выполнить следующие действия:
    1. Выполнить команду npm init, которая создаст файл package.json.
    2. Добавить библиотеки azure-pipelines-task-lib через команду npm install azure-pipelines-task-lib –save.
    3. Добавить внешние библиотеки через команды npm install @types/node —save-dev и npm install @types/q —save-dev.
    4. Добавить решение для создания запросов к сервису через команду npm install xmlhttprequest –save.
    5. Добавить решение для кодирования личного ключа доступа к сервису npm install buffer —save.
    6. Создать файл настройки компиляции tsconfig.json через команду tsc –init. В данном файле устанавливаем целевую версию typescript «target»: «es6».

Создание расширения

Файл описания задачи

Перед написанием основного исходного кода, необходимо сформировать файл описания задачи для определения сборки или релиза. Для этого необходимо создать файл task.json, который описывает задачу и ее параметры. Содержимое файла приблизительно следующее:

{

«id»: «c6ff84bf-0260-47d6-889d-6c2ecbbe2aa5»,

«name»: «CreateWorkItemCustomTask»,

«friendlyName»: «Create New Work Item Custom Task»,

«description»: «Create a new work item and link it to a new build or release»,

«helpMarkDown»: «»,

«category»: «Utility»,

«author»: «Aleksandr Shamrai»,

«version»: {

«Major»: 0,

«Minor»: 1,

«Patch»: 32

},

«instanceNameFormat»: «New Work Item $(workitemtype) $(titletemplate)»,

«inputs»: [

{

«name»: «workitemtype»,

«type»: «pickList»,

«label»: «Worm Item Type»,

«defaultValue»: «Task»,

«required»: true,

«helpMarkDown»: «Select the type for new work item»,

«options»: {

«Task»: «Task»,

«Bug»: «Bug»

}

},

{

«name»: «titletemplate»,

«type»: «string»,

«label»: «Title Template»,

«defaultValue»: «»,

«required»: false,

«helpMarkDown»: «A title template»

},

{

«name»: «assignedto»,

«type»: «string»,

«label»: «Assigne to»,

«defaultValue»: «»,

«required»: false,

«helpMarkDown»: «Set an owner of a work item»

},

{

«name»: «linktobuild»,

«type»: «radio»,

«label»: «Link New Work Item to Build»,

«defaultValue»: «No»,

«required»: true,

«helpMarkDown»: «Link a new work item to build»,

«options»: {

«No»: «No»,

«LinkAsArtifact»: «Link as artifact (only for builds)»,

«LinkAsWebUrl»: «Link as Web Url»

}

}

],

«execution»: {

«Node»: {

«target»: «index.js»

}

}

}

Полное описание формата файла можно найти здесь: https://github.com/Microsoft/azure-pipelines-task-lib/blob/master/tasks.schema.json

В нашем случае основные пункты:

  1. Id – уникальный идентификатор
  2. Name – наименование задачи без пробелов.
  3. friendlyName – описательное наименование задачи
  4. category – категория, в которой мы найдем нашу задачу
  5. author – автор задачи
  6. instanceNameFormat – как данный шаг будет отражаться в списке задач сборки или релиза.
  7. Inputs – список входных параметров для задачи. Каждый параметр имеет следующие основные элементы:
    1. Name – наименование параметра
    2. Type – тип параметра (boolean, filePath, multiLine, pickList, radio, secureFile, string).
    3. Label – название параметра на форме задачи
  8. Execution – описание того, что нужно выполнять. В данном случае будет выполняться файл index.js, который создается ниже.

Исполняемый код задачи

Создадим файл index.ts, который будет содержать основной код. В данном файле можно выделить следующие моменты:

  • Как основная запускаемая функция используется функция run, которая детализируется под конкретные задачи.
  • Для получения входных параметров задачи, которые описаны в «task.json», используется метод getInput с передачей наименования параметра.
  • Для получения переменных окружения используется метод getVariable. Все переменные окружения, которые присутствуют при выполнении задачи можно посмотреть здесь: Default and custom release variables and debugging. При этом в рамках задачи используются следующие важные переменные:
    • System.AccessToken – содержит персональный ключ доступа к сервису. При этом доступ к нему обеспечивается отдельно в самом определении сборки или релиза в параметре Allow scripts to access the OAuth token. Если данный параметр не будет выставлен, то авторизация будет невозможна.
    • System.TeamFoundationCollectionUri – адрес сервера TFS.
    • System.TeamProject – командный проект, в котором выполняется сборки или развертывается релиз.
    • И т.д.

Пример получение значения параметров и переменных окружения:

const inputWIType: string = tl.getInput(‘workitemtype’, true);

const inputTitle: string = tl.getInput(‘titletemplate’, false);

const inputAssignedTo: string = tl.getInput(‘assignedto’, false);

const inputLinkToBuild: string = tl.getInput(‘linktobuild’, true);

const strAC = tl.getVariable(‘System.AccessToken’);

if (strAC == null)

{

tl.setResult(tl.TaskResult.Failed, ‘Access to OAuth token is not allowed’);

return;

}

const strServiceUrl = tl.getVariable(‘System.TeamFoundationCollectionUri’);

const strTeamProjectName = tl.getVariable(‘System.TeamProject’);

  • Создание рабочего элемента выполняется на основе запроса Rest Api Work Items – Create. Код для выполнения запроса следующий:
let devRequest = new XMLHttpRequest();

let encodedData = new Buffer(«:» + strAC).toString(‘base64’);

devRequest.open(«POST», strServiceUrl + strTeamProjectName + urlCreateTask)

devRequest.setRequestHeader(‘Authorization’, ‘Basic ‘ + encodedData);

devRequest.setRequestHeader(‘Accept’, ‘application/json’);

devRequest.setRequestHeader(‘Content-Type’, ‘application/json-patch+json’);

devRequest.send(JSON.stringify(patchFields));

devRequest.onreadystatechange = function () {

if (devRequest.readyState === 4) {

let newWorkItem = JSON.parse(devRequest.responseText);

if («id» in newWorkItem)

console.log(«The work item has been created», newWorkItem.id);

else

console.log(‘Error’,devRequest.responseText);

}

}

В данном примере создается запрос на основе авторизации Personal Access Token с использования адреса для создания нового рабочего элемента:

POST http://{server_name}:{port}/{collection name}/{project}/_apis/wit/workitems/${type}?api-version=2.0

В тело запроса в формате JSON добавляется список создаваемых полей и связей с другими объектами:

  • Для указания содержимого в поле применяется формат:
[

{

«op»: «add»,

«path»: «/fields/System.Title»,

«from»: null,

«value»: «Sample task»

}

]

  • Для создания новой гиперссылки используется формат:
[

{

«op»: «add»,

«path»: «/relations/-«,

«value»: {

«rel»: «Hyperlink»,

«url»: «URL»

}

}

]

  • Для создания ссылки на сборку используется следующий формат:
[

{

«op»: «add»,

«path»: «/relations/-«,

«value»: {

«rel»: «ArtifactLink»,

«url»: «artifact URI»,

«attributes»: {«name»:»Build»}

}

}

]

Компиляция решения

Для формирования файла index.js необходимо выполнить в каталоге исходного кода команду tsc.

Файл манифест расширения

Манифест расширения описывает расширение для TFS и создается через файл vss-extension.json. Файл содержит следующее:

{

«manifestVersion»: 1,

«id»: «new-work-item-custom-task»,

«name»: «Create New Work Item Custom Task»,

«version»: «0.1.32»,

«publisher»: «AShamrai»,

«targets»: [

{

«id»: «Microsoft.TeamFoundation.Server»

}

],

«description»: «Create a new work item and link it a build or release»,

«content»: {

«details»: {

«path»: «details.md»

}

},

«categories»: [

«Build and release»

],

«icons»: {

«default»: «images/newworkitem.png»

},

«files»: [

{

«path»: «NewWICustomTask»

}

],

«contributions»: [

{

«id»: «mew-work-tem-custom-build-release-task»,

«type»: «ms.vss-distributed-task.task»,

«targets»: [

«ms.vss-distributed-task.tasks»

],

«properties»: {

«name»: «NewWICustomTask»

}

}

]

}

Описание важных пунктов:

  • Id – уникальный идентификатор задачи
  • Targets:id – целевая платформа
  • Contributions:Id – уникальный идентификатор задачи
  • Сontributions :type – тип задачи
  • Contributions:targets – целевые задачи, в которых будет участвовать расширение.
  • Contributions:properties:name – наименование задачи, которое совпадает с каталогом, котором находятся скомпилированные исходники.
  • Files: path – путь к каталогу с содержимым задачи.

Полная спецификация содержимого находится по этому адресу: Extension manifest reference.

Сборка решения

Для сборки решения необходимо из каталога решения выполнить команду:

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

Установка

Для развертывания решения можно выполнить следующие шаги:

  • Перейти на страницу управления расширениями Team Foundation Server. Она обычно находится по адресу http://server_name:8080/tfs/_gallery/manage. На этой странице необходимо нажать кнопку Upload new extension, найти сформированный после сборки решения файл расширения и выполнить его установку. Эта операция установит решение в сервер.

Рисунок 1. Страница управления расширениями

  • После того как появилось решение в списке, мы нажимаем на его ссылку и выполняем установку на необходимую коллекцию проектов.

Рисунок 2. Развертывание решения в необходимой коллекции

  • После развертывания решения мы можем приступить к созданию необходимого определения сборки или релиза.

Рисунок 3. Новая задача в списке утилит

  • При этом нужно помнить, что для того, чтобы решение могло взаимодействовать с сервером, необходимо дать ему возможность получить персональный код доступа, который используется агентом сборки для доступа к серверу.

Рисунок 4. Доступ к персональному ключу доступа

  • Результат можно увидеть в логах выполнения сборки или релиза, а также в виде созданного рабочего элемента.

Рисунок 5. Лог работы задачи

Рисунок 6. Новый рабочий элемент, который ссылается на сборку

Добавить комментарий

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

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход /  Изменить )

Google photo

Для комментария используется ваша учётная запись Google. Выход /  Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход /  Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход /  Изменить )

Connecting to %s

 
%d такие блоггеры, как: