gifts2017

Автоматическая интеграция внешних обработок в конфигурацию 1C

Опубликовал Андрей Комар (akomar) в раздел Программирование - Практика программирования

Вот уже некоторое время мы ведем разработку через git-flow. Все очень нравится. Но есть один момент - когда выходит релиз и ветка develop мигрирует в ветку master, очень лень подключать новые внешние обработки к базе вручную. Вот поэтому я решил немного подковырять Jenkins для небольшой автоматизации процесса.

Итак, что нам нужно:

  1. Конфигурация с поддержкой БСП.
  2. Jenkins который выведен «наружу».
  3. Python.
  4. Три или четыре кружки кофе(шутка)

Задумка следующая: у нас исходники хранятся на bitbucket, значит нужно интегрировать его из Jenkins, чтобы когда мы делали merge ветки develop в master, CI подхватывал все это добро и самостоятельно подключал к базе.

ШАГ 1. ОБРАБОТКА-ИНТЕГРАТОР НА 1С.

Данная обработка вызывается CI в пакетном режиме. Как параметр запуска передается список полных путей к файлам которые нужно подключить к базе. Многие штуки (интеграция из чатом Slack, подключение внешней обработки/отчета) у нас уже интегрированы в конфигурацию. Обработка парсит параметры запуска и подключает файлики к базе. После подключения приходит сообщение в корпоративный чат о результатах. Если файлика еще нет в базе – его необходимо подключить вручную. Вот небольшие фрагменты кода.

Код который парсит параметры запуска и помещает файлы во временное хранилище.

&НаКлиенте
Функция ПоместитьВнешниеОбработкиВХранилище(ПараметрЗапуска)

   
МассивСтрок     = СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок(ПараметрЗапуска, ";");
   
МассивОшибок    = Новый Массив;
   
МассивАдресов   = Новый Массив;

    Для каждого
СтрокаИзМассива Из МассивСтрок Цикл

       
Сообщить(СтрокаИзМассива);

       
Файл = Новый Файл(СтрокаИзМассива);
        Если Не
Файл.Существует() Тогда
           
СообщениеОбОшибке = НСтр("ru='Файл не найден.'", ОбщегоНазначенияКлиентСервер.КодОсновногоЯзыка());
           
МассивОшибок.Добавить(Новый Структура("Сообщение, ПутьКФайлу", СообщениеОбОшибке, СтрокаИзМассива));
            Продолжить;
        КонецЕсли;

       
АдресФайла = "";
        Если НЕ
ПоместитьФайл(АдресФайла, СтрокаИзМассива, , Ложь, УникальныйИдентификатор) Тогда
           
СообщениеОбОшибке = НСтр("ru='Не удалось загрузить файл на сервер.'", ОбщегоНазначенияКлиентСервер.КодОсновногоЯзыка());
           
МассивОшибок.Добавить(Новый Структура("Сообщение, ПутьКФайлу", СообщениеОбОшибке, СтрокаИзМассива));
            Продолжить;
        КонецЕсли;

       
МассивАдресов.Добавить(Новый Структура("ПутьКФайлу, АдресФайла, ИмяФайла, РасширениеФайла", СтрокаИзМассива, АдресФайла, Файл.ИмяБезРасширения, Файл.Расширение));

    КонецЦикла;

    Возврат Новый
Структура("МассивАдресов, МассивОшибок", МассивАдресов, МассивОшибок);

КонецФункции
// ПоместитьВнешниеОбработкиВХранилище()

Здесь также происходит заполнение служебных структур и массив (МассивАдресов, МассивОшибок) для последующей обработки данных.

А вто код, который подключает обработки к базе с помощтью функционала БСП.

&НаСервере
Функция ВыполнитьПодключениеДоступныхОбработок(МассивАдресов)

   
ТекстСообщения = "";

    Для каждого
АдресОбработки Из МассивАдресов Цикл

       
ИмяВнОбработки  = ВнешниеОбработки.Подключить(АдресОбработки.АдресФайла, , Ложь);
       
СозданныйОбъект = ВнешниеОбработки.Создать(ИмяВнОбработки);

        Попытка
           
СведенияОВнешнейОбработке = СозданныйОбъект.СведенияОВнешнейОбработке();
        Исключение
           
ШаблонСообщения = "Внешняя обработка _%1_ имеет неправильный формат данных.";
           
ШаблонСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонСообщения, АдресОбработки.ПутьКФайлу);
           
ТекстСообщения  = ТекстСообщения + ШаблонСообщения + Символы.ПС;
            Продолжить;
        КонецПопытки;

       
ОбработкаСсылка = Справочники.ДополнительныеОтчетыИОбработки.НайтиПоНаименованию(СведенияОВнешнейОбработке.Наименование);
        Если
ОбработкаСсылка.Пустая() Тогда
           
ШаблонСообщения = "Внешняя обработка _%1_ еще не подключена к базе. Первый раз обработку нужно подключить вручную.";
           
ШаблонСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонСообщения, АдресОбработки.ПутьКФайлу);
           
ТекстСообщения  = ТекстСообщения + ШаблонСообщения + Символы.ПС;
            Продолжить;
        КонецЕсли;

       
ПараметрыРегистрации = ПолучитьПараметрыРегистрацииОбработки();

        Если
ВРег(АдресОбработки.РасширениеФайла) = ".ERF" Тогда
           
ПараметрыРегистрации.ЭтоОтчет = Истина;
        ИначеЕсли
ВРег(АдресОбработки.РасширениеФайла) = ".EPF" Тогда
           
ПараметрыРегистрации.ЭтоОтчет = Ложь;
        Иначе
           
ШаблонСообщения = "Внешняя обработка _%1_ не может быть подключена к базе. Расширение файла не соответствует расширению внешнего отчета (ERF) или обработки (EPF).";
           
ШаблонСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонСообщения, АдресОбработки.ПутьКФайлу);
           
ТекстСообщения  = ТекстСообщения + ШаблонСообщения + Символы.ПС;
            Продолжить;
        КонецЕсли;

       
ПараметрыРегистрации.ИмяФайла = АдресОбработки.ИмяФайла;
       
ПараметрыРегистрации.АдресДанныхОбработки = АдресОбработки.АдресФайла;

       
ОбработкаОбъект = ОбработкаСсылка.ПолучитьОбъект();

        Попытка
           
ДополнительныеОтчетыИОбработки.ЗарегистрироватьОбработку(ОбработкаОбъект, ПараметрыРегистрации);
        Исключение
           
ШаблонСообщения = "Обработку _%1_ не удалось автоматически подключить к базе.";
           
ШаблонСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонСообщения, АдресОбработки.ПутьКФайлу);
           
ТекстСообщения  = ТекстСообщения + ШаблонСообщения + Символы.ПС;
        КонецПопытки;

       
ОбработкаОбъект.Записать();

       
ШаблонСообщения = "Обработка _%1_ успешно автоматически подключена к базе.";
       
ШаблонСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонСообщения, АдресОбработки.ПутьКФайлу);
       
ТекстСообщения  = ТекстСообщения + ШаблонСообщения + Символы.ПС;

    КонецЦикла;

    Возврат
ТекстСообщения;

КонецФункции
// ВыполнитьПодключениеДоступныхОбработок()

В коде сразу генерируются служебные сообщения, которые потом будут выведены в корпоративный чатик.

Шаг 2. Скрипт на Python.

Идея скрипта состоит в том, чтобы через команду git diff сравнить локальный master и master удаленный, а файлы которые изменились – записать в базу. Скрипт состоит из нескольких логических блоков. Первый блок делает пресловутый git diff и получает список измененных файлов.

def getStringWithChangedFiles(gitexepath, branchtocompare, repopath):

    try:
        fileList = subprocess.check_output([gitexepath, 'diff', branchtocompare, '--name-only']).decode("utf-8")
    except subprocess.CalledProcessError:
        raise Exception('Не удалось выполнить команду получения списка измененных файлов.')

    stringWithChangedFiles = ''

    print(fileList)

    for fileName in fileList.split("\n"):
        if not ('epf' in fileName or 'erf' in fileName):
            continue
        if not stringWithChangedFiles:
            stringWithChangedFiles = repopath + "\\" + fileName
        else:
            stringWithChangedFiles += ';' + repopath + "\\" + fileName

    return stringWithChangedFiles

Участок кода который запускает 1С в пакетном режиме и передает на вход обработки из шага №1 список измененных файлов.

def getStringWithChangedFiles(gitexepath, branchtocompare, repopath):

    try:
        fileList = subprocess.check_output([gitexepath, 'diff', branchtocompare, '--name-only']).decode("utf-8")
    except subprocess.CalledProcessError:
        raise Exception('Не удалось выполнить команду получения списка измененных файлов.')

    stringWithChangedFiles = ''

    print(fileList)

    for fileName in fileList.split("\n"):
        if not ('epf' in fileName or 'erf' in fileName):
            continue
        if not stringWithChangedFiles:
            stringWithChangedFiles = repopath + "\\" + fileName
        else:
            stringWithChangedFiles += ';' + repopath + "\\" + fileName

    return stringWithChangedFiles

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

ШАГ 3. КОНФИГУРИРУЕМ JENKINS.

 Перейдем к самому вкусному - конфигурированию нашего job-а. Для начала укажем репозиторий откуда тянем изменения.

Указываем репозиторий

Далее необходимо указать что удаленный мастер будет копироваться в локальную ветку localmaster (в конце мы делаем merge).

Настройка веткиСледующая настройка – самая важная для интеграции из bitbucket, а именно – генерирование токена аутентификации. Он нам нужен чтобы bitbucket мог запускать jobs на нашем CI удаленно. Токен должен быть сверхсекретным ;)

Authentication token

Ну и следующая настройка – непосредственный вызов скрипта через пункт Execute Windows batch command.

Запуск скрипта

ШАГ 4. НАСТРОЙКИ BITBUCKET HOOK.

Чтобы bitbucket мог дергать наш CI нам нужно настроить так называемый Jenkins Hook. Перейдем в настройки репозитория в раздел Integrations подраздел Hooks. В меню Select a hook выберем пункт Jenkins.

Bitbucket hook

Нам нужно заполнить всего три поля. Endpoint – сюда пишем адрес нашего CI сервера в формате http|s://username:password@domain:port/path, где username - User ID, а password - API Token. Посмотреть данные настройки можно если пойти в меню People, далее выбрать пользователя и открыть секцию API Token из настроек.

API Token

Project name – имя проекта, который мы выбрали в Jenkins. Здесь нужно заметить, что имена job-ам нужно стараться давать без пробелов, а если у вас установлен плагин для каталогов в списке проектов, путь к проекту будет выглядеть так Auto_deploy/job/Auto_deploy_test, где Auto_deploy – имя каталога, Auto_deploy_test – имя проекта.

Поле Token содержит наш токен аутентификации, который мы сгенерировали на шаге №3.

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

Результаты работы

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

Оригинал статьи. Happy Coding :-)



См. также

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