Введение.
Эта статья подойдет для тех, кто имеет по крайней мере базовые знания и навык работы с git. Она разработана для разработки с помощью модели ветвления Git Flow.
Формат версии конфигурации 1С это A.B.C.[h], где:
- A – главный номер версии (major version number).
- B – вспомогательный номер версии (minor version number).
- C – номер сборки, номер логической итерации по работе над функционалом версии A.B (build number).
- h – Немедленные изменения/исправления конфигурации (hotfix branches), при которых конфигурация обновляется вручную (незапланированно), и не приводят к автоматическому обновлению конфигурации.
Представленный механизм так же подойдет для интеграции в среду Jenkins, но выходит за пределы темы статьи и рассматриваться не будет.
Итак, начнем!
В конфигурацию нужно добавить http-сервис, с корневым url - api. Добавим ему шаблон "/v1/{action}/" с методом GET. Обработчик у метода будет следующий:
Action = НРег(Запрос.ПараметрыURL["action"]);
Если Action = "version" Тогда
HTTPОтвет = Новый HTTPСервисОтвет(200);
HTTPОтвет.УстановитьТелоИзСтроки(Метаданные.Версия);
Возврат HTTPОтвет;
ИначеЕсли Action = "telegram" И Не Запрос.Заголовки.Получить("Text") = Неопределено Тогда
HTTPСоединение = Новый HTTPСоединение("api.telegram.org", 443, , , , , Новый ЗащищенноеСоединениеOpenSSL);
ПараметрыЗапроса = Новый Соответствие;
Текст = Запрос.Заголовки.Получить("Text");
ПараметрыЗапроса.Вставить("Content-type", "application/json");
TelegramBotID = Константы.Update_TelegramBotID.Получить();
TelegramChatID = Константы.Update_TelegramChatID.Получить();
Если ЗначениеЗаполнено(TelegramBotID) И ЗначениеЗаполнено(TelegramChatID) Тогда
МассивЧатов = СтрРазделить(TelegramChatID, ";");
Для Каждого ЧатID Из МассивЧатов Цикл
HTTPЗапрос = Новый HTTPЗапрос(TelegramBotID + "/sendMessage?chat_id=" + ЧатID
+ "&parse_mode=html&text=" + Текст, ПараметрыЗапроса);
HTTPСоединение.Получить(HTTPЗапрос);
КонецЦикла;
КонецЕсли;
HTTPОтвет = Новый HTTPСервисОтвет(200);
Возврат HTTPОтвет;
ИначеЕсли Action = "disconnect" Тогда
Port = Запрос.Заголовки.Получить("Port");
MainPort = Запрос.Заголовки.Получить("MainPort");
AgentSrv = Запрос.Заголовки.Получить("AgentSrv");
BaseName = Запрос.Заголовки.Получить("BaseName");
login = Запрос.Заголовки.Получить("login");
password = Запрос.Заголовки.Получить("password");
СистемнаяИнфо = Новый СистемнаяИнформация;
ПодстрокиВерсии = СтрРазделить(СистемнаяИнфо.ВерсияПриложения, ".");
COMСоединитель = Новый COMОбъект("v" + ПодстрокиВерсии[0] + ПодстрокиВерсии[1] + ".COMConnector");
СтрокаСоединенияСАгентомСервера = "tcp://" + AgentSrv + ":" + Port;
СоединениеСАгентомСервера = COMСоединитель.ConnectAgent(СтрокаСоединенияСАгентомСервера);
ПеремКластер = Неопределено;
Для Каждого Кластер Из СоединениеСАгентомСервера.GetClusters() Цикл
Если Формат(Кластер.MainPort, "ЧГ=0;") = MainPort Тогда
СоединениеСАгентомСервера.Authenticate(Кластер, login, password);
ПеремКластер = Кластер;
Прервать;
КонецЕсли;
КонецЦикла;
Если ПеремКластер = Неопределено Тогда
HTTPОтвет = Новый HTTPСервисОтвет(400);
HTTPОтвет.УстановитьТелоИзСтроки("ERROR: Не удалось найти кластер");
Возврат HTTPОтвет;
КонецЕсли;
ПеремОписаниеИнформационнойБазы = Неопределено;
Для Каждого ОписаниеИнформационнойБазы Из СоединениеСАгентомСервера.GetInfoBases(ПеремКластер) Цикл
Если НРег(ОписаниеИнформационнойБазы.Name) = НРег(BaseName) Тогда
ПеремОписаниеИнформационнойБазы = ОписаниеИнформационнойБазы;
Прервать;
КонецЕсли;
КонецЦикла;
Если ПеремОписаниеИнформационнойБазы = Неопределено Тогда
HTTPОтвет = Новый HTTPСервисОтвет(400);
HTTPОтвет.УстановитьТелоИзСтроки("ERROR: Не удалось найти базу");
Возврат HTTPОтвет;
КонецЕсли;
ВсеПользователи = Истина;
Сеансы = СоединениеСАгентомСервера.GetInfoBaseSessions(ПеремКластер, ПеремОписаниеИнформационнойБазы);
Для Каждого Сеанс Из Сеансы Цикл
Попытка
СоединениеСАгентомСервера.TerminateSession(ПеремКластер, Сеанс);
Исключение
ВсеПользователи = Ложь;
КонецПопытки;
КонецЦикла;
Если Не ВсеПользователи Тогда
HTTPОтвет = Новый HTTPСервисОтвет(400);
HTTPОтвет.УстановитьТелоИзСтроки("ERROR: Не удалось отключить всех пользователей");
Возврат HTTPОтвет;
КонецЕсли;
HTTPОтвет = Новый HTTPСервисОтвет(200);
Возврат HTTPОтвет;
ИначеЕсли Action = "check" Тогда
HTTPОтвет = Новый HTTPСервисОтвет(?(Константы.Update_ЗапретАвтообновления1С.Получить(), 400, 200));
Возврат HTTPОтвет;
КонецЕсли;
HTTPОтвет = Новый HTTPСервисОтвет(200);
Возврат HTTPОтвет;
далее короткое описание для каждого Action в методе:
- version - Основной метод, возвращает текущую версию конфигурации
- telegram - метод, который оповещает о процессе обновления, с помощью bota. Можно заменить на оповещения по электронной почте, смс и тд.
- disconnect - метод, который завершает работу пользователей перед обновлением (позволяет отключать пользователей в конфигурациях без БСП)
- check - метод, в который можно добавить нужные проверки перед обновлением. Например, проверку создания backup обновляемой базы, дня недели, выполнение важных регламентных заданий при которых нельзя обновлять конфигурацию и тд
Следующим пунктом опишем скрипт, который выполняет обновление баз. Он запускается с помощью скриптового языка OneScript.
Файл update1C.os
#Использовать irac
#Использовать cmdline
#Использовать 1commands
Функция ПолучитьМассивБазДляОбновления()
МассивНастроеек = Новый Массив();
МассивБазДляОбновления = Новый Массив();
СтруктураНастроеек = Новый Структура();
//Расположение проекта
СтруктураНастроеек.Вставить("КаталогПроекта", "C:\Users\admin\git\test_base_1");
//Файлы конфигурации проекта edt
СтруктураНастроеек.Вставить("PROJECT", "C:\Users\admin\git\test_base_1\conf");
БазаДанных = Новый Структура();
//Заголовок для сообщения в телеграмме
БазаДанных.Вставить("Заголовок", " TEST UPDATE BASE");
//Сервер публикации информационной базы
БазаДанных.Вставить("СерверHttp", "localhost");
//Сервер БД
БазаДанных.Вставить("СерверБазыДанных", "192.168.1.1\SQL1");
//Кластер сервера
БазаДанных.Вставить("СерверКластера", "localhost");
//Имя базы данных
БазаДанных.Вставить("ИмяБазыДанных", "test_developer");
//Пользователь БД
БазаДанных.Вставить("ПользовательБазыДанных", "sql_login");
//Пароль пользователя БД
БазаДанных.Вставить("ПарольБазыДанных", "sql_password");
//Пользователь 1С
БазаДанных.Вставить("Пользователь1С", "update1C");
//Пароль пользоватлея 1С
БазаДанных.Вставить("Пароль1С", "update1C");
//URL http-сервиса
БазаДанных.Вставить("АдресHttp", "test_developer/hs/api/v1");
//Порт агента сервера
БазаДанных.Вставить("Port", "1540");
//Порт менеджера кластрера
БазаДанных.Вставить("MainPort", "1541");
//Логин кластера сервера 1С
БазаДанных.Вставить("ClustersLogin", "log");
//Пароль кластера сервера 1С
БазаДанных.Вставить("ClustersPassword", "pswd");
МассивБазДляОбновления.Добавить(БазаДанных);
БазаДанных = Новый Структура();
БазаДанных.Вставить("Заголовок", " TEST UPDATE BASE 2");
БазаДанных.Вставить("СерверHttp", "localhost");
БазаДанных.Вставить("СерверБазыДанных", "192.168.1.2\SQL2");
БазаДанных.Вставить("СерверКластера", "localhost");
БазаДанных.Вставить("ИмяБазыДанных", "test_developer2");
БазаДанных.Вставить("ПользовательБазыДанных", "sql_login");
БазаДанных.Вставить("ПарольБазыДанных", "sql_password");
БазаДанных.Вставить("Пользователь1С", "update1C");
БазаДанных.Вставить("Пароль1С", "update1C");
БазаДанных.Вставить("АдресHttp", "test_developer2/hs/api/v1");
БазаДанных.Вставить("Port", "1540");
БазаДанных.Вставить("MainPort", "1541");
БазаДанных.Вставить("ClustersLogin", "log");
БазаДанных.Вставить("ClustersPassword", "pswd");
МассивБазДляОбновления.Добавить(БазаДанных);
СтруктураНастроеек.Вставить("МассивБазДляОбновления", МассивБазДляОбновления);
МассивБазДляОбновления = Новый Массив();
СтруктураНастроеек = Новый Структура();
СтруктураНастроеек.Вставить("КаталогПроекта", "C:\Users\admin\git\test_base_2");
СтруктураНастроеек.Вставить("PROJECT", "C:\Users\admin\git\test_base_2\conf");
БазаДанных = Новый Структура();
БазаДанных.Вставить("Заголовок", " TEST UPDATE BASE 3");
БазаДанных.Вставить("СерверHttp", "localhost");
БазаДанных.Вставить("СерверБазыДанных", "192.168.1.3\SQL3");
БазаДанных.Вставить("СерверКластера", "localhost");
БазаДанных.Вставить("ИмяБазыДанных", "test_developer3");
БазаДанных.Вставить("ПользовательБазыДанных", "sql_login");
БазаДанных.Вставить("ПарольБазыДанных", "sql_password");
БазаДанных.Вставить("Пользователь1С", "update1C");
БазаДанных.Вставить("Пароль1С", "update1C");
БазаДанных.Вставить("АдресHttp", "test_developer3/hs/api/v1");
БазаДанных.Вставить("Port", "1540");
БазаДанных.Вставить("MainPort", "1541");
БазаДанных.Вставить("ClustersLogin", "log");
БазаДанных.Вставить("ClustersPassword", "pswd");
МассивБазДляОбновления.Добавить(БазаДанных);
СтруктураНастроеек.Вставить("МассивБазДляОбновления", МассивБазДляОбновления);
МассивНастроеек.Добавить(СтруктураНастроеек);
Возврат МассивНастроеек;
КонецФункции
// Получает ветку текущего релиза
//
// Параметры:
// ТекстовыйДокумент - ТекстовыйДокумент - данные по веткам
// АктуальнаяВерсияЧислом - Число - Версия текущего релиза числом
//
// Возвращаемое значение:
// - Строка - Имя ветки текщего релиза
Функция ПолучитьНачалоЛога(ТекстовыйДокумент,АктуальнаяВерсияЧислом)
Ветки = ТекстовыйДокумент.КоличествоСтрок();
Для к=1 По Ветки Цикл
Ветка = СокрЛП(ТекстовыйДокумент.ПолучитьСтроку(к));
Если СтрНачинаетсяС(Ветка, "origin/release/") Тогда
СтрокаВетки = СтрЗаменить(Ветка, "origin/release/", "");
ПроверяемаяВерсия = ВерсияЧислом(СтрокаВетки);
Если ПроверяемаяВерсия = АктуальнаяВерсияЧислом Тогда
Возврат Ветка;
КонецЕсли;
КонецЕсли;
КонецЦикла;
Возврат "";
КонецФункции
// Преобразует строку версии в число, сокращая до 3-го разряда
//
// Параметры:
// ВерсияСтрокой - Строка - Версия в формате ХХ.ХХ.ХХ.ХХ
//
// Возвращаемое значение:
// - Число - Версия в числовом эквиваленте
Функция ВерсияЧислом(Знач ВерсияСтрокой)
Разрядность = СтрНайти(ВерсияСтрокой, ".", , , 3);
Если Разрядность > 0 Тогда
ВерсияСтрокой = Лев(ВерсияСтрокой, Разрядность-1);
КонецЕсли;
Если ПустаяСтрока(ВерсияСтрокой) Или ВерсияСтрокой = "0.0.0.0" Тогда
Возврат 0;
КонецЕсли;
Разряд = 0;
Результат = 0;
ОписаниеТипаЧисло = Новый ОписаниеТипов("Число");
Остаток = ВерсияСтрокой;
ПозицияТочки = СтрНайти(Остаток, ".");
Пока ПозицияТочки > 0 Цикл
ЧислоСтрокой = Лев(Остаток, ПозицияТочки - 1);
Число = ОписаниеТипаЧисло.ПривестиЗначение(ЧислоСтрокой);
Результат = Результат * 1000 + Число;
Остаток = Сред(Остаток, ПозицияТочки + 1);
ПозицияТочки = СтрНайти(Остаток, ".");
Разряд = Разряд + 1;
КонецЦикла;
Число = ОписаниеТипаЧисло.ПривестиЗначение(Остаток);
Результат = Результат * 1000 + Число;
Разряд = Разряд + 1;
// Номера версии после 4 точки возвращает после запятой.
// Например, для версии "1.2.3.4.5.6.7" вернет 1002003004,005006007.
Если Разряд > 4 Тогда
Результат = Результат / Pow(1000, Разряд - 4);
КонецЕсли;
Возврат Результат;
КонецФункции
//Глобальные переменные (общие для всех баз)
СМАЙЛ_ЗЕЛЕНЫЙ_КРУГ = "🟢";
СМАЙЛ_КРАСНЫЙ_КРУГ = "🔴";
СМАЙЛ_ИТОГ_ЗЕЛЕНЫЙ = "c89;";
СМАЙЛ_ИТОГ_КРАСНЫЙ = "c40;";
WORKSPACE = "C:\Users\admin\git\WS";
XML = "C:\Users\admin\git\XML";
LOGFILE="C:\Users\admin\workspace\log.txt";
BRANCH="C:\Users\admin\workspace\branch.txt";
LOGCOMMIT="C:\Users\admin\workspace\log_commit.txt";
//xx.xxxx заменить на версию 1С (например 22.1923)
ibcmd = "C:\Program Files\1cv8\8.3.xx.xxxx\bin\ibcmd.exe";
dir_backup = "D:\BACKUP\";
МассивБаз = ПолучитьМассивБазДляОбновления();
Для Каждого СтруктураОбновления ИЗ МассивБаз Цикл
Команда = Новый Команда;
Релиз = "0.0.0";
НачалоЛога = "";
ОкончаниеЛога = "";
ТекстовыйДокументBRANCH = Новый ТекстовыйДокумент;
//Переходи в кактлог проекта и загружаем коммиты, скачиваем все удаленные ветки.
// Ищем релизные и записываем их в файл
Команда.УстановитьСтрокуЗапуска("cd "
+ СтруктураОбновления.КаталогПроекта
+ " & git fetch & git branch -r | find ""origin/release/"" > """
+ BRANCH + """ 2>&1");
КодВозврата = Команда.Исполнить();
ТекстовыйДокументBRANCH.Прочитать(BRANCH);
МаксВерсияЧислом = ВерсияЧислом("0.0.0");
Ветки = ТекстовыйДокументBRANCH.КоличествоСтрок();
Для к=1 По Ветки Цикл
Ветка = СокрЛП(ТекстовыйДокументBRANCH.ПолучитьСтроку(к));
Если СтрНачинаетсяС(Ветка, "origin/release/") Тогда
СтрокаВетки = СтрЗаменить(Ветка, "origin/release/", "");
ПроверяемаяВерсия = ВерсияЧислом(СтрокаВетки);
Если ПроверяемаяВерсия > МаксВерсияЧислом Тогда
МаксВерсияЧислом = ПроверяемаяВерсия;
ОкончаниеЛога = Ветка;
Релиз = СтрокаВетки;
КонецЕсли;
КонецЕсли;
КонецЦикла;
//проверка что релиз обновился
Если НЕ Релиз = "0.0.0" Тогда
КонфигурацияГотоваКЗагрузке = Ложь;
Для Каждого База ИЗ СтруктураОбновления.МассивБазДляОбновления Цикл
HTTPСоединение = Новый HTTPСоединение(База.СерверHttp);
Заголовки = Новый Соответствие();
HTTPЗапрос = Новый HTTPЗапрос(База.АдресHttp + "/version", Заголовки);
Результат = HTTPСоединение.Получить(HTTPЗапрос);
//если сервис недоступен, проверяем след базу
Если НЕ Результат.КодСостояния = 200 Тогда
Продолжить;
КонецЕсли;
АктуальнаяВерсия = Результат.ПолучитьТелоКакСтроку();
АктуальнаяВерсияЧислом = ВерсияЧислом(АктуальнаяВерсия);
//Начинаем формировать сообщения для отправки в теелграмм
СообщениеТелеграм = " Релиз: " + Релиз + "</b>";
Если АктуальнаяВерсияЧислом < МаксВерсияЧислом Тогда
Если НЕ КонфигурацияГотоваКЗагрузке Тогда
//Переключаемся на релизную ветку и обновляем ее с сервера
Команда.УстановитьСтрокуЗапуска("cd " + СтруктураОбновления.КаталогПроекта
+ " & git checkout " + ОкончаниеЛога + " & git pull");
КодВозврата_checkout = Команда.Исполнить();
СообщениеТелеграм = СообщениеТелеграм + Символы.ПС
+ ?(КодВозврата_checkout <= 1, СМАЙЛ_ЗЕЛЕНЫЙ_КРУГ, СМАЙЛ_КРАСНЫЙ_КРУГ)
+ " получение данных с GitHub";
//Очищаем каталоги для сборки. Удалив их и создав заново
Команда.УстановитьСтрокуЗапуска("rd /S /Q """ + WORKSPACE
+ """ & rd /S /Q """ + XML+ """");
КодВозврата_rd = Команда.Исполнить();
Команда.УстановитьСтрокуЗапуска("md """ + WORKSPACE
+ """ & md """ + XML+ """");
КодВозврата_md = Команда.Исполнить();
СообщениеТелеграм = СообщениеТелеграм + Символы.ПС
+ ?(КодВозврата_rd+КодВозврата_md = 0, СМАЙЛ_ЗЕЛЕНЫЙ_КРУГ, СМАЙЛ_КРАСНЫЙ_КРУГ)
+ " подготовка структуры каталогов";
//Экспорт проекта в xml-выгрузку конфигурации
//xxxx.x.x заменить на версию edt (например 2022.2.5)
Команда.УстановитьСтрокуЗапуска("ring edt@xxxx.x.x:x86_64 workspace export --project """
+ СтруктураОбновления.PROJECT
+ """ --configuration-files """ + XML
+ """ --workspace-location """ + WORKSPACE + """ >> """
+ LOGFILE + """ 2>&1");
КодВозврата_export = Команда.Исполнить();
СообщениеТелеграм = СообщениеТелеграм + Символы.ПС
+ ?(КодВозврата_export = 0, СМАЙЛ_ЗЕЛЕНЫЙ_КРУГ, СМАЙЛ_КРАСНЫЙ_КРУГ)
+ " выгрузка конфигурации в XML";
КонфигурацияГотоваКЗагрузке = Истина;
КонецЕсли;
СообщениеЛогаКоммитов = "";
КодВозврата_apply = 1;
КодВозврата_import = 1;
Если КонфигурацияГотоваКЗагрузке Тогда
НачалоЛога = ПолучитьНачалоЛога(ТекстовыйДокументBRANCH, АктуальнаяВерсияЧислом);
//получаем для отображения информацию о коммитах
Если ЗначениеЗаполнено(НачалоЛога) И ЗначениеЗаполнено(ОкончаниеЛога) Тогда
ТекстовыйДокумент = Новый ТекстовыйДокумент;
Команда.УстановитьСтрокуЗапуска("cd " + СтруктураОбновления.КаталогПроекта
+ " & git shortlog --pretty=format:""%an: %b"" --merges "
+ НачалоЛога + ".." + ОкончаниеЛога
+ " --grep=""release"" --invert-grep > """
+ LOGCOMMIT + """ 2>&1");
КодВозврата_log = Команда.Исполнить();
ТекстовыйДокумент.Прочитать(LOGCOMMIT);
СообщениеЛогаКоммитов = Символы.ПС + "<code>Задачи в релизе:"
+ Символы.ПС + ТекстовыйДокумент.ПолучитьТекст() + "</code>";
КонецЕсли;
//для удобства разделим в логе базы
Команда.УстановитьСтрокуЗапуска("echo %date% " + База.ИмяБазыДанных
+ " >> """ + LOGFILE + """ 2>&1");
КодВозврата = Команда.Исполнить();
//Завершение работы активных пользователей
Заголовки = Новый Соответствие();
Заголовки.Вставить("Port", База.Port);
Заголовки.Вставить("MainPort", База.MainPort);
Заголовки.Вставить("BaseName", База.ИмяБазыДанных);
Заголовки.Вставить("login", База.ClustersLogin);
Заголовки.Вставить("password", База.ClustersPassword);
Заголовки.Вставить("AgentSrv", База.СерверКластера);
HTTPЗапрос = Новый HTTPЗапрос(База.АдресHttp + "/disconnect",Заголовки);
Результат = HTTPСоединение.Получить(HTTPЗапрос);
СообщениеТелеграмБаза = СообщениеТелеграм + Символы.ПС
+ ?(Результат.КодСостояния = 200, СМАЙЛ_ЗЕЛЕНЫЙ_КРУГ, СМАЙЛ_КРАСНЫЙ_КРУГ)
+ " завершение активных сеансов";
//получаем имя файла бекапа
ИмяБД = База.ИмяБазыДанных;
//если нужно добавлять, а не перезаписывать
//ИмяБД = База.ИмяБазыДанных+Формат(ТекущаяДата(),"ДФ=_ггггММдд");
//Делаем бекап базы перед обновлением
Команда.УстановитьСтрокуЗапуска("sqlcmd -S " + База.СерверБазыДанных
+ " -U """ + База.ПользовательБазыДанных
+ """ -P """ + База.ПарольБазыДанных
+ """ -b -Q ""BACKUP DATABASE " + База.ИмяБазыДанных
+ " TO DISK = N'"+dir_backup+ИмяБД+".bak' WITH COMPRESSION, NOFORMAT, INIT, NAME = N'"
+ ИмяБД + "', SKIP, NOREWIND, NOUNLOAD, STATS = 10, CHECKSUM"" >> """ + LOGFILE + """ 2>&1");
КодВозврата_backup = Команда.Исполнить();
Если КодВозврата_backup = 0 Тогда
СообщениеТелеграмБаза = СообщениеТелеграмБаза + Символы.ПС
+ ?(КодВозврата_backup = 0, СМАЙЛ_ЗЕЛЕНЫЙ_КРУГ, СМАЙЛ_КРАСНЫЙ_КРУГ)
+ " BACKUP: " + ИмяБД;
//Импорт конфигурации из XML с помощью утилиты ibcmd
Команда.УстановитьСтрокуЗапуска(""""+ibcmd
+""" infobase config import --dbms=MSSQLServer --db-server=" + База.СерверБазыДанных
+ " --db-name=" + База.ИмяБазыДанных
+ " --db-user="+База.ПользовательБазыДанных
+ " --db-pwd="""+База.ПарольБазыДанных
+ """ --user="+База.Пользователь1С
+ " --password="+База.Пароль1С
+ " """+XML+""" >> """+LOGFILE+""" 2>&1");
КодВозврата_import = Команда.Исполнить();
СообщениеТелеграмБаза = СообщениеТелеграмБаза + Символы.ПС
+ ?(КодВозврата_import = 0, СМАЙЛ_ЗЕЛЕНЫЙ_КРУГ, СМАЙЛ_КРАСНЫЙ_КРУГ)
+ " загрузка конфигурации в базу из XML";
//Обновление конфигурации
Команда.УстановитьСтрокуЗапуска(""""+ibcmd
+ """ infobase config apply --dbms=MSSQLServer --db-server="+База.СерверБазыДанных
+ " --db-name="+База.ИмяБазыДанных
+ " --db-user="+База.ПользовательБазыДанных
+ " --db-pwd="""+База.ПарольБазыДанных
+ """ --user="+База.Пользователь1С
+ " --password="+База.Пароль1С
+ " --force >> """+LOGFILE+""" 2>&1");
КодВозврата_apply = Команда.Исполнить();
СообщениеТелеграмБаза = СообщениеТелеграмБаза + Символы.ПС
+ ?(КодВозврата_apply = 0, СМАЙЛ_ЗЕЛЕНЫЙ_КРУГ, СМАЙЛ_КРАСНЫЙ_КРУГ)
+ " обновление конфигурации";
Иначе
СообщениеЛогаКоммитов = "";
СообщениеТелеграмБаза = СообщениеТелеграм + Символы.ПС
+ СМАЙЛ_КРАСНЫЙ_КРУГ + " ОШИБКА создания BACKUP";
КонецЕсли;
Иначе
СообщениеТелеграмБаза = СообщениеТелеграм + Символы.ПС
+ СМАЙЛ_КРАСНЫЙ_КРУГ + " ОШИБКА экспорта конфигурации в файл";
КонецЕсли;
СообщениеТелеграмБаза = "<b>" + ?(КодВозврата_md+КодВозврата_export+КодВозврата_import+КодВозврата_apply = 0,
СМАЙЛ_ИТОГ_ЗЕЛЕНЫЙ, СМАЙЛ_ИТОГ_КРАСНЫЙ)
+ База.Заголовок + СообщениеТелеграмБаза + СообщениеЛогаКоммитов;
//Отправка сообщения в телеграмм
Заголовки = Новый Соответствие();
Заголовки.Вставить("Text", КодироватьСтроку(СообщениеТелеграмБаза, СпособКодированияСтроки.КодировкаURL));
HTTPЗапрос = Новый HTTPЗапрос(База.АдресHttp + "/telegram",Заголовки);
Результат = HTTPСоединение.Получить(HTTPЗапрос);
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецЦикла;
Краткое описание работы скрипта.
Сначала формируется список параметров и массив баз для обновления. В дальнейшем что бы добавить или удалить базу редактируем в файле функцию ПолучитьМассивБазДляОбновления. Далее получаем актуальные данные веток и коммитов из git-а (который подключен по ssh). Получаем текущий релиз базы (версию в 1С), и сравниваем его с релизными ветками (release/*). Если есть новый релиз, тогда переключаемся на ветку релиза и скачиваем изменения. Подготавливаем структуру каталогов и экспортируем в нее проект edt в виде xml файлов. Перед обновлением делаем бекап базы. Если все прошло без ошибок, тогда в каждую конфигурацию, из массива, мы загружаем данные проекта из xml-файлов, и обновляем ее. В самом конце отправляем сообщение из 1С в зависимости от настроек.
Пример.
Посмотрим, что получается в итоге. На примере, перехода с релиза 0.1.9 на 0.1.10 тестовой конфигурации. В каждой релизной ветке повышаем релиз (версию конфигурации) на следующий. На скриншоте видно, что после релиза 0.1.9 у нас было несколько коммитов, а также в релизной ветке мы изменили версию конфигурации на 0.1.10.
Запускаем выполнение скрипта командой из cmd или вешаем на планировщик заданий в ОС Windows. Например, запуск из командной строке выглядит так
oscript C:\scripts\update1C.os
После выполнения скрипта получаем сообщение в чат с ботом и обновленную конфигурацию до 0.1.10. На скриншоте видно что сначала скачиваются данные и из них обновляются первые 2 базы, при чем вторая с некритической ошибкой. А вот третяя база не обновлеяется из за ошибки создания бекапа.
Если что-то не работает, смотрим логи в файле %LOGFILE%
Ссылки: