Как стать автором
Обновить

Комментарии к задаче в Битрикс24 при коммите для Mercurial

Время на прочтение11 мин
Количество просмотров7.4K
image С каждым полугодием команда 1С-Битрикс презентует новый функционал облачных корпоративных порталов Битрикс24. Одной из востребованных функций портала можно назвать «Задачи», позволяющие Битрикс24 занимать места в рейтинге таск-трекеров (например, Количество и качество: как развиваются таск-трекеры в условиях конкуренции). Поэтому многие веб-студии, особенно связанные с разработкой на 1С-Битрикс и Битрикс24, используют функционал задач в разработке.

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

В связи с этим и возникла необходимость отправлять информацию о ходе разработки во время коммитов, что бы фиксировать все изменения в комментариях к задачам не отвлекаясь на написание комментариев к ней — достаточно добавить информативный комментарий при коммите.

В работе используется VCS Mercurial, для которой и описана настройка отправки информации о коммите в комментарии задачи портала.

Для отправки комментариев при коммите Mercurial в портал Битрикс24 необходимо проделать следующие шаги:

  1. На сайте, где будет размещаться приложение необходимо наличие SSL-сертификата.

  2. Установить используя composer следующие пакеты:
    • mesilov/bitrix24-php-sdk — обёртка на php для работы с BX24 REST API
    • defuse/php-encryption — необходима для формирования ключа доступа

    Установка осуществляется командой
     $ composer require "mesilov/bitrix24-php-sdk: ^0.2.0" "defuse/php-encryption: ^2.0"
    

  3. Загрузить на сайт файлы приложения:
    • install.php — установочный файл приложения для Битрикс24. Необходим для получения приложением токенов доступа при установке приложения.
      install.php
      <?php
      /**
       * Установка приложения.
       *
       * Выполнить из окружения портала Битрикс24 для создания конфигурационного файла
       */
      error_reporting(E_ALL & ~E_NOTICE);
      
      require __DIR__ . '/vendor/autoload.php';
      require __DIR__ . '/lib.php';
      
      if (null === $_REQUEST['DOMAIN'] || null === $_REQUEST['member_id'] || null === $_REQUEST['AUTH_ID'] || null === $_REQUEST['REFRESH_ID']) {
          die('Приложение необходимо установить из портала Битрикс24');
      }
      
      $params = AddMessageToBitrix24Task::load();
      
      if (0 === count($params)) {
          $params = [
              //Идентификатор приложения в портале (из настроек приложения в портале)
              'B24_APPLICATION_ID'     => '<CLIENT_ID>',
              //Секретное слово приложения в портале (из настроек приложения в портале)
              'B24_APPLICATION_SECRET' => '<CLIENT_SECRET>',
              //Требуемые для работы сущности портала (из настроек приложения в портале)
              'B24_APPLICATION_SCOPE'  => ['task'],
              //URL приложения после установки (из настроек приложения в портале)
              'B24_REDIRECT_URI'       => 'https://<APP_DOMAIN>/app.php',
              //Домен портала
              'DOMAIN'                 => $_REQUEST['DOMAIN'],
              //Уникальный идентификатор приложения
              'MEMBER_ID'              => $_REQUEST['member_id'],
              //Токен авторизации
              'AUTH_ID'                => $_REQUEST['AUTH_ID'],
              //Токен обновления
              'REFRESH_ID'             => $_REQUEST['REFRESH_ID'],
          ];
      
          //Сохранить настройки в кофигурационный файл
          AddMessageToBitrix24Task::save($params);
      }
      
      //Проверка, что настроки сохранены корректно
      if (AddMessageToBitrix24Task::check()) {
          //Загружаем настройки для вывода в интерфейсе Битрикс24 ключа доступа
          $params = AddMessageToBitrix24Task::load();
          $result = 'Приложение установлено.<br>';
          $result .= 'Добавьте в скрипт hook.php ключ доступа:<br>';
          $result .= $params['KEY'];
      } else {
          $result = 'Приложение установлено c ошибками.<br>';
      }
      die($result);
      

    • app.php — основной файл приложения, добавляющий комментарии к задачам при срабатывании хука Mercurial…
      app.php
      <?php
      /**
       * Приложение добавляющее комментарии к указанной задаче
       */
      error_reporting(E_ALL & ~E_NOTICE);
      
      require __DIR__ . '/vendor/autoload.php';
      require __DIR__ . '/lib.php';
      
      //Загрузить настройки
      $params = AddMessageToBitrix24Task::load();
      
      try {
          //Формируем ключ для проверки
          $key = $params['B24_APPLICATION_ID'] . $params['MEMBER_ID'] . $params['B24_APPLICATION_SECRET'];
      
          //Дешифруем полученный ключ и сравниваем с текущим
          if (AddMessageToBitrix24Task::decrypt($_REQUEST['key']) !== $key) {
              die('Некорректный ключ доступа');
          }
      } catch (Exception $e) {
          die('Некорректный формат ключа доступа');
      }
      
      if (!is_numeric($_REQUEST['task'])) {
          die('Не задан номер задачи');
      }
      
      if (null === $_REQUEST['message'] || '' === trim($_REQUEST['message'])) {
          die('Не задан комментарий');
      }
      
      try {
          //Получить объект для работы с Bitrix24
          $bx24 = AddMessageToBitrix24Task::getBX24Instance($params);
          //Добавить комментарий к задаче
          $result = AddMessageToBitrix24Task::add($bx24, $_REQUEST['task'], $_REQUEST['message']);
          die($result);
      } catch (Exception $e) {
          die('Ошибка при доавлении комментария к задаче');
      }
      

    • lib.php — набор функций, необходимых для работы приложения
      lib.php
      <?php
      /**
       * Основной класс приложения
       */
      use Defuse\Crypto\Crypto;
      use Defuse\Crypto\Key;
      
      /**
       * Добавить комментарий к задачи в портале Битрикс24
       *
       * Class AddMessageToBitrix24Task
       */
      class AddMessageToBitrix24Task
      {
          /**
           * @var string Путь к настройкам приложения. Файл не должен находится в корне сайта.
           */
          private static $config = __DIR__ . '/../bx24.auth';
      
          /**
           * @var string Ключ шифрования
           */
          private static $safeKey;
      
          /**
           * Шифровать переменную
           *
           * @param string $var Переменная для шифрования
           *
           * @return string Шифрованная переменная
           *
           * @throws \Defuse\Crypto\Exception\BadFormatException
           * @throws \Defuse\Crypto\Exception\EnvironmentIsBrokenException
           */
          public static function encrypt($var)
          {
              return Crypto::encrypt($var, self::getKey());
          }
      
          /**
           * Дешифровать переменую
           *
           * @param string $var Переменная для дешифрации
           *
           * @return string Дешифрованная переменная
           *
           * @throws \Defuse\Crypto\Exception\BadFormatException
           * @throws \Defuse\Crypto\Exception\EnvironmentIsBrokenException
           */
          public static function decrypt($var)
          {
              return Crypto::decrypt($var, self::getKey());
          }
      
          /**
           * Получить ключ шифрования
           *
           * @return Key Ключ шифрования
           *
           * @throws \Defuse\Crypto\Exception\BadFormatException
           * @throws \Defuse\Crypto\Exception\EnvironmentIsBrokenException
           */
          public static function getKey()
          {
              if (null === self::$safeKey) {
                  $params = self::load();
      
                  //Получить ключ шифрования в бинарно-безопасном виде
                  if (null === $params || null === $params['PRIVATE_KEY']) {
                      self::$safeKey = Key::createNewRandomKey()->saveToAsciiSafeString();
                  } else {
                      self::$safeKey = $params['PRIVATE_KEY'];
                  }
              }
      
              return Key::loadFromAsciiSafeString(self::$safeKey);
          }
      
          /**
           * Получить объект для работы с Bitrix24
           *
           * @param array $params Параметры для работы с Битрикс24
           *
           * @return \Bitrix24\Bitrix24 Объект для работы с Битрикс24
           *
           * @throws \Bitrix24\Bitrix24Exception
           * @throws \Defuse\Crypto\Exception\BadFormatException
           * @throws \Defuse\Crypto\Exception\EnvironmentIsBrokenException
           */
          public static function getBX24Instance(array $params)
          {
              $bx24 = new \Bitrix24\Bitrix24(false);
      
              $bx24->setApplicationScope($params['B24_APPLICATION_SCOPE']);
              $bx24->setApplicationId($params['B24_APPLICATION_ID']);
              $bx24->setApplicationSecret($params['B24_APPLICATION_SECRET']);
              $bx24->setRedirectUri($params['B24_REDIRECT_URI']);
              $bx24->setDomain($params['DOMAIN']);
              $bx24->setMemberId($params['MEMBER_ID']);
              $bx24->setAccessToken($params['AUTH_ID']);
              $bx24->setRefreshToken($params['REFRESH_ID']);
      
              //Если время жизни токенов истекло
              if ($bx24->isAccessTokenExpire()) {
                  //ПОлучитть новый токен доступа
                  $temp = $bx24->getNewAccessToken();
                  //Обновить токены в объекте
                  $params['AUTH_ID'] = $temp['access_token'];
                  $params['REFRESH_ID'] = $temp['refresh_token'];
                  $bx24->setAccessToken($params['AUTH_ID']);
                  $bx24->setRefreshToken($params['REFRESH_ID']);
                  //Сохранить обновленные токены
                  self::save($params);
              }
      
              return $bx24;
          }
      
          /**
           * Добавить комментарий к задаче
           *
           * @param \Bitrix24\Bitrix24 $bx24    Объект для работы с Битрикс24
           * @param    int             $task    Идентификатор задачи
           * @param    string          $message Комментарий
           *
           * @return string
           */
          public static function add(\Bitrix24\Bitrix24 $bx24, $task, $message)
          {
              $str = '';
      
              try {
                  //Проверить есть ли такая задача на портале
                  $bx24->call(
                      'task.item.getdata',
                      [
                          'TASKID' => $task
                      ]
                  );
      
                  $str .= 'Задача #' . $task . ' на портале ' . $bx24->getDomain() . ' найдена' . PHP_EOL;
      
                  //Добавить комментарий к задаче
                  $bx24->call(
                      'task.commentitem.add',
                      [
                          'TASKID' => $task,
                          'FIELDS' => [
                              'POST_MESSAGE' => $message
                          ]
                      ]
                  );
      
                  $str .= 'Комментарий к задаче успешно добавлен';
              } catch (Exception $e) {
                  $str .= 'Ошибка при добавлении комментация к задаче';
              }
      
              return $str;
          }
      
          /**
           * Сохранить настройки в конфигурационный файл
           *
           * @param array $params Настройки
           *
           * @return bool
           *
           * @throws \Defuse\Crypto\Exception\BadFormatException
           * @throws \Defuse\Crypto\Exception\EnvironmentIsBrokenException
           */
          public static function save(array $params)
          {
              //Ключ для доступа к приложению для добавления комментария
              $params['KEY'] = AddMessageToBitrix24Task::encrypt($params['B24_APPLICATION_ID'] . $params['MEMBER_ID'] . $params['B24_APPLICATION_SECRET']);
              //Ключ шифрования
              $params['PRIVATE_KEY'] = self::$safeKey;
              //Сохраняем данные в файл конфигурации
              $result = json_encode($params, JSON_UNESCAPED_UNICODE);
      
              return file_put_contents(self::$config, $result) > 0;
          }
      
          /**
           * Получить настройки из конфигурационного файла
           *
           * @return array Настройки
           */
          public static function load()
          {
              if (!file_exists(self::$config)) {
                  return [];
              }
      
              //Получить настройки приложения
              $params = file_get_contents(self::$config);
      
              return json_decode($params, true);
          }
      
          /**
           * Проверка, что приложение установлено из заданого портала Битрикс24.
           *
           * @return bool
           */
          public static function check()
          {
              try {
                  $params = AddMessageToBitrix24Task::load();
                  $bx24 = self::getBX24Instance($params);
      
                  $result = $bx24->call('app.info');
      
                  return $result['result']['CODE'] === $params['B24_APPLICATION_ID'];
              } catch (\Exception $e) {
                  return false;
              }
          }
      }
      

  4. Загрузить на web-сервер, где используется VCS Mercurial файл hghook-commit-to-bx24.php, выполняющий обращение к приложению при коммите. Размещать файл необходимо вне корня сайта. Для работы скрипта необходимо наличие следующих функций:
    • shell_exec — выполнение консольных команд для формирования информации о коммите
    • curl_exec — для отправки данных в приложение
    hghook-commit-to-bx24.php
    <?php
    /**
     * Хук срабатывающий после выполнения команды hg commit
     */
    
    //Адрес приложения Битрикс24
    define('BX24_APP_URL', 'https://<APP_DOMAIN>/app.php');
    
    //Ключ для обращения к приложению. Получить можно после установки из конфигурационного файла
    define('KEY', '<ACCESS_KEY>');
    
    echo 'Запущен хук Mercurial, добавляющий информацию о коммите в задачу на портал' . PHP_EOL;
    
    if(!function_exists('shell_exec')){
        echo 'Ошибка: функция «shell_exec» недоступна' . PHP_EOL;
        echo 'Завершение хука' . PHP_EOL;
        exit(0);
    }
    
    if(!function_exists('curl_exec')){
        echo 'Ошибка: функция «curl_exec» недоступна' . PHP_EOL;
        echo 'Завершение хука' . PHP_EOL;
        exit(0);
    }
    
    //Путь к исполняемому файлу Mercurial
    $hg = $_SERVER['HG'];
    
    if (!is_file($hg) || !is_executable($hg)) {
        echo 'Ошибка: не найден исполняемый файл Mercurial' . PHP_EOL;
        echo 'Завершение хука' . PHP_EOL;
        exit(0);
    }
    
    echo 'Получение информации о коммите' . PHP_EOL;
    
    //Получить полное название хоста, на котором работает Mercurial
    $hostname = trim(shell_exec('hostname -f'));
    
    //Абсолютный путь к текущему репозиторию
    $pwd = $_SERVER['PWD'];
    
    //Текущая активная ветка Mercurial
    $branch = shell_exec("$hg branch");
    
    //Получаем информацию о сделанном коммите
    $log = trim(shell_exec("$hg log -l 1"));
    
    //Автор коммита
    $matches = null;
    $user = preg_match('/user:\s+(?<user>\S.*)/ium', $log, $matches) ? $matches['user'] : 'unknown';
    
    //Комментарий коммита
    $summary = preg_match('/summary:\s+(?<summary>\S.*)/ium', $log, $matches) ? $matches['summary'] : '';
    
    //Получить список файлов текущего коммита за исключюенеи удаленных
    $files = trim(shell_exec("$hg st -amr"));
    
    //Количество файлов текущего коммита
    $filesCount = substr_count($files, PHP_EOL);
    
    //Получить номер задачи из названия текущей ветки Mercurial или из комментария к коммиту
    echo 'Поиск номера задачи в названии ветки или комментарии' . PHP_EOL;
    
    $task = 0;
    
    if (preg_match('/^task[#\@\$](?<id>\d+)/iu', $branch, $matches)) {
        $task = (int)$matches['id'];
    } elseif (preg_match('/^task[#\@\$](?<id>\d+)/iu', $summary, $matches)) {
        $task = (int)$matches['id'];
    }
    
    //Если номер не обнаружен, то предлагаем пользователю его ввести
    if ($task <= 0) {
        echo 'Номер задачи не найден' . PHP_EOL;
        echo 'Введите номер задачи на портале или нажмите Enter, чтобы пропустить: ';
        $count = fscanf(STDIN, "%d\n", $task);
    
        if ($count <= 0) {
            echo 'Номер задачи не введен.' . PHP_EOL;
            echo 'Информация о коммите не будет отправлена на портал' . PHP_EOL;
            echo 'Завершение хука' . PHP_EOL;
            exit(0);
        }
    }
    
    echo 'Отправка информации о коммите на портал' . PHP_EOL;
    
    $message = <<<EOT
    Новый набор изменений закоммичен пользователем $user в $pwd на $hostname:
    $summary
    ======
    Техническая информация о коммите:
    $log
    
    Список закоммиченных файлов (всего $filesCount шт):
    $files
    
    Комментарий сгенерирован автоматически.
    EOT;
    
    //Данные для отправки
    $postData = [
        'message' => $message,
        'task'    => $task,
        'key'     => KEY
    ];
    
    //Формируем запрос к приложению
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, BX24_APP_URL);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
    $result = curl_exec($ch);
    
    echo $result . PHP_EOL;
    echo 'Завершение хука' . PHP_EOL;
    

  5. Добавить в hgrc путь к загруженному файлу hghook-commit-to-bx24.php
    [hooks]
    commit = php -f /home/bitrix/hghook-commit-to-bx24.php
    

  6. Выбрать в левом меню портала пункт «Добавить приложение», если оно не видно, то развернуть пункт «Приложения»

  7. На странице выбираем тип приложения «Для личного пользования», так как мы его не собираемся выкладывать в облачный Маркетплейс
    Выбор типа приложения
    image

  8. На странице настроек нового приложения указываем
    • Название приложения
    • Название пункта меню на нужном языке
    • Установить права доступа на «Задачи (task)»
    • Указываем ссылку на исполняемый файл приложения
    • Указываем ссылку на установочный файл приложения
    Настройки приложения
    image

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

  9. После сохранения приложения мы попадаем на страницу со списком приложений. Для каждого приложения Битрикс24 присваивает два уникальных параметра «Код приложения (client_id)» и «Ключ приложения (client_secret)», которые необходимо указать в файле install.php
    Список приложений
    image

  10. Теперь необходимо перейти к установке приложения, кликнув по ссылке на приложение в левом меню. Если все сделано верно, то будет показано сообщение вида
    Приложение установлено.
    Добавьте в скрипт hghook-commit-to-bx24.php ключ доступа:
    <ACCESS_KEY>
    

    Установка приложения
    image

    Если ничего не было выведено (белая область вместо приложения), то скорее всего у вас установлен заголовок
    Header set X-Frame-Options SAMEORIGIN
    

    Он запрещает показывать ваш сайт во фреймах. Что бы исправить это, в директории с приложением достаточно создать (или отредактировать) файл .htaccess, добавив строку
    Header unset X-Frame-Options
    

    Полученный код доступа необходимо записать в файл hghook-commit-to-bx24.php

  11. Если всё корректно настроено, то для добавления информации о коммите к задаче потребуется её номер. Номер задачи в Битрикс24 отображается около ее названия.
    Задача в портале
    image

    Для добавления информации о коммите к задаче можно указать номер в тексте коммита в самом начале после «task#», «task@» или «task$».
    [bitrix@dhcppc5 www]$ hg st
    M composer.json
    [bitrix@dhcppc5 www]$ hg ci -u testuser -m 'task#62 Выполнен пункт #1 чеклиста: сделано то-то и то-то'
    Запущен хук Mercurial, добавляющий информацию о коммите в задачу на портал
    Получение информации о коммите
    Поиск номера задачи в названии ветки или комментарии
    Отправка информации о коммите на портал
    Задача #62 на портале <PORTAL_NAME>.bitrix24.ru найдена
    Комментарий к задаче успешно добавлен
    Завершение хука
    [bitrix@dhcppc5 www]$
    

    Комментарий к задаче #1
    image

    Также можно получить номер задачи из названия рабочей ветки Mercurial, если она имеет название начинающееся с «task#», «task@» или «task$».

    Если номер задачи не найден ни в комментарии, ни в названии ветки, то его можно ввести вручную.
    [bitrix@dhcppc5 www]$ hg ci -u testuser -m 'Выполнен пункт #2 чеклиста: сделано то-то и то-то'
    Запущен хук Mercurial, добавляющий информацию о коммите в задачу на портал
    Получение информации о коммите
    Поиск номера задачи в названии ветки или комментарии
    Номер задачи не найден
    Введите номер задачи на портале или нажмите Enter, чтобы пропустить: 62
    Отправка информации о коммите на портал
    Задача #62 на портале <PORTAL_NAME>.bitrix24.ru найдена
    Комментарий к задаче успешно добавлен
    Завершение хука
    [bitrix@dhcppc5 www]$
    

    Комментарий к задаче #2
    image

    Если ввод номера задачи пропущен, то комментарий не будет отправлен.
    [bitrix@dhcppc5 www]$ hg ci -u testuser -m 'Выполнен пункт #3 чеклиста: сделано то-то и то-то'
    Запущен хук Mercurial, добавляющий информацию о коммите в задачу на портал
    Получение информации о коммите
    Поиск номера задачи в названии ветки или комментарии
    Номер задачи не найден
    Введите номер задачи на портале или нажмите Enter, чтобы пропустить:
    Номер задачи не введен
    Информация о коммите не будет отправлена на портал
    Завершение хука
    [bitrix@dhcppc5 www]$
    

    Если будет указан несуществующий номер задачи, то будет выведено соответствующее уведомление об ошибке.
    [bitrix@dhcppc5 www]$ hg ci -u testuser -m 'task$65445642 Выполнен пункт #3 чеклиста: сделано то-то и то-то'
    Запущен хук Mercurial, добавляющий информацию о коммите в задачу на портал
    Получение информации о коммите
    Поиск номера задачи в названии ветки или комментарии
    Отправка информации о коммите на портал
    Ошибка при добавлении комментария к задаче
    Завершение хука
    [bitrix@dhcppc5 www]$

Код из статьи.

Использованные материалы:
Теги:
Хабы:
Всего голосов 6: ↑2 и ↓4-2
Комментарии3

Публикации

Истории

Работа

Ближайшие события