1. Проблема
2. Решение
Для автоматизации процесса был разработан Jenkins-пайплайн, который берет на себя всю подготовку ветки типовых релизов в Git-репозитории.
def nodeNameAgent = "ИмяСервера"
def nodeNamePost = "ИмяСервера"
def nodeNameSQL = "ИмяСервера"
def count = 0
def cf2EDT(String version, String Repository, String BranchName, String DestinyFormat, String vPlatform, String EDTversion, String SourceFolder, int releaseCount) {
script {
try {
if (releaseCount == 1) {
source_path = ""
} else {
source_path = readFile("$WORKSPACE\\source").trim()
project_path = readFile("$WORKSPACE\\project").trim()
if (DestinyFormat == "XML" && source_path.isEmpty()) {
source_path = "src\\cf\\"
}
}
echo "Обрабатываем версию: ${version}"
// Подготовка
bat encoding: 'UTF-8', script: """@echo off
chcp 65001 > nul
echo ---------------------------
echo Подготавливаем ${releaseCount}й релиз...
echo ---------------------------
echo Исходные данные:
echo версия платформы 1С: ${vPlatform}, версия EDT: ${EDTversion}
echo Репозиторий: ${Repository}, ветка: ${BranchName}
echo папка с релизами: ${SourceFolder}
echo Обрабатываем версию: ${version}, формат исходников: ${DestinyFormat}
rd /s /q "$WORKSPACE\\temp" > nul 2>&1 & md "$WORKSPACE\\temp" > nul
rd /s /q "$WORKSPACE\\db" > nul 2>&1 & md "$WORKSPACE\\db" > nul
rd /s /q "$WORKSPACE\\xml" > nul 2>&1 & md "$WORKSPACE\\xml" > nul
rd /s /q "$WORKSPACE\\ws" > nul 2>&1 & md "$WORKSPACE\\ws" > nul
if ${releaseCount} GTR 1 (
if "${source_path}"=="" exit 1
rd /s /q "$WORKSPACE\\${source_path}" > nul 2>&1 & md "$WORKSPACE\\${source_path}" > nul
echo путь к исходникам: "$WORKSPACE\\${source_path}"
)
"""
// sleep 5
// Создаем временную базу
bat encoding: 'UTF-8', script: """@echo off
chcp 65001 > nul
echo -----------------------
echo Создаем временную базу
echo -----------------------
set search_dir=${SourceFolder}\\${version}
dir /s /b "%search_dir%" | findstr /i /e "1Cv8.cf" > temp_file.txt
set /p CF_path=<temp_file.txt
del /f /q temp_file.txt
echo берем CF из: %CF_path%
"%PROGRAMW6432%\\1cv8\\${vPlatform}\\bin\\ibcmd.exe" infobase create --data="$WORKSPACE\\temp" --db-path="$WORKSPACE\\db" --create-database --load="%CF_path%"
if not ERRORLEVEL 0 (exit 1)
"""
// Применяем изменения. иначе с поддержки база не снимется
bat encoding: 'UTF-8', script: """@echo off
chcp 65001 > nul
echo -------------------------
echo Сохраняем Конфигурацию...
echo -------------------------
echo [INFO] Обновление конфигурации базы данных...
"%PROGRAMW6432%\\1cv8\\${vPlatform}\\bin\\ibcmd.exe" infobase config apply --data="$WORKSPACE\\temp" --db-path="$WORKSPACE\\db" --user="" --password="" --force > nul
if not ERRORLEVEL 0 (exit 1)
echo [INFO] Обновление конфигурации базы данных успешно завершено
"""
// Снимаем базу с поддержки
bat encoding: 'UTF-8', script: """@echo off
chcp 65001 > nul
echo -------------------------
echo Снимаем базу с поддержки
echo -------------------------
"%PROGRAMW6432%\\1cv8\\${vPlatform}\\bin\\ibcmd.exe" infobase config support disable --data="$WORKSPACE\\temp" --db-path="$WORKSPACE\\db" --user="" --password="" --force
if not ERRORLEVEL 0 (exit 1)
"""
if (releaseCount == 1) {
// Инициализируем или клонируем репозиторий
bat encoding: 'UTF-8', script: """@echo off
chcp 65001 > nul
echo -------------------------
echo Проверяем репозиторий
echo -------------------------
echo [INFO] Проверяем существование репозитория: ${Repository}
git ls-remote git@gitlab:1c/${Repository}.git > nul 2>&1
if %ERRORLEVEL% == 0 (
echo [INFO] Репозиторий "${Repository}" существует.
echo ----------------------
echo Клонируем репозиторий
echo ----------------------
git clone git@gitlab:1c/${Repository}.git > nul 2>&1
robocopy "$WORKSPACE\\${Repository}" "$WORKSPACE" /MOVE /E /NFL /NDL /NJH /NJS
git checkout -B ${BranchName}
) else (
echo [INFO] Репозиторий "${Repository}" не найден.
echo -------------------------
echo Инициализируем репозиторий
echo -------------------------
git init
git branch -M ${BranchName}
echo . > .gitignore > nul
if "${DestinyFormat}"=="EDT" xcopy "\\\\%server%\\SHARE\\script\\edt_project\\*" "$WORKSPACE\\edt" /E /I /Y > nul
)
echo %ERRORLEVEL%
"""
// определяем исходные папки
if (DestinyFormat == "EDT") {
config_name = "Configuration.mdo"
echo 'формат EDT'
} else {
config_name = "Configuration.xml"
echo 'формат XML'
}
bat encoding: 'UTF-8', script: """@echo off
setlocal enabledelayedexpansion
dir /s /b "$WORKSPACE" | findstr /i /e "${config_name}" > source
set /p full_path=<source
echo найден корень: %full_path%
set base_path=$WORKSPACE\\
set target_path=!full_path:%base_path%=!
if "${DestinyFormat}"=="EDT" set "result=!target_path:\\Configuration\\${config_name}=!"
if "${DestinyFormat}"=="XML" set "result=!target_path:\\${config_name}=!"
echo %result% > source
set target=%result%\\
for /f "tokens=1 delims=\\ " %%A in ("%target%") do set "result=%%A"
echo %result% > project
endlocal
"""
source_path = readFile("$WORKSPACE\\source").trim()
project_path = readFile("$WORKSPACE\\project").trim()
echo "путь к проекту: ${project_path}"
echo "путь к исходникам: ${source_path}"
}
// Выгружаем исходники в xml
bat encoding: 'UTF-8', script: """@echo off
chcp 65001 > nul
echo -------------------------
echo Выгружаем исходники в XML
echo -------------------------
"%PROGRAMW6432%\\1cv8\\${vPlatform}\\bin\\ibcmd.exe" infobase config export --data="$WORKSPACE\\temp" --db-path="$WORKSPACE\\db" --user="" --password="" --force "$WORKSPACE\\xml"
if not ERRORLEVEL 0 (exit 1)
"""
if (DestinyFormat == "EDT") {
// Конвертируем XML в формат EDT
bat encoding: 'UTF-8', script: """@echo off
setlocal enabledelayedexpansion
chcp 65001 > nul
echo -----------------------------
echo Конвертируем XML в формат EDT
echo -----------------------------
set EDT_mask=%PROGRAMW6432%\\1C\\1CE\\components\\1c-edt-${EDTversion}*
dir "%EDT_mask%" /B /AD > edt.txt
set /p EDTCLI_dir=<edt.txt & del edt.txt > nul
set EDTCLI_dir=%EDTCLI_dir: =%
echo каталог EDT: "%EDTCLI_dir%"
set EDTCLI_path=%PROGRAMW6432%\\1C\\1CE\\components\\%EDTCLI_dir%
rd /s /q "$WORKSPACE\\${source_path}"
call "%EDTCLI_path%\\1cedtcli.exe" -data "$WORKSPACE\\ws" -command import --project "$WORKSPACE\\${project_path}" --configuration-files "$WORKSPACE\\xml" --version "%vPlatform%"
if not ERRORLEVEL 0 (exit 1)
echo [INFO] Конвертация в формат EDT - завершена
rem echo [INFO] Оптимизация формата хранения данных проекта
rem call "%EDTCLI_path%\\1cedtcli.exe" -data "$WORKSPACE\\ws" -command clean-up-source --project "$WORKSPACE\\edt"
rem if not ERRORLEVEL 0 (
rem echo [ERROR] возникла ошибка при Оптимизации
rem endlocal
rem exit 1
rem ) else (
rem echo [INFO] Оптимизация - завершена
rem endlocal
rem )
"""
}
// Отправляем изменения в репозиторий
bat encoding: 'UTF-8', script: """@echo off
chcp 65001 > nul
echo -------------------------
echo Добавляем в репозиторий
echo -------------------------
echo Сохраняем релиз: "${version}" в ветку "${BranchName}"
git add ${project_path}\\
rem git add xml\\
git commit -m "типовая ${version}" > nul
git tag -a ${version} -m "${version}"
"""
} catch (Exception e) {
currentBuild.description = "Ошибка обработки версии ${version}"
error("Произошла ошибка: ${e.message}")
}
}
}
pipeline {
agent {
label "${nodeNameAgent}"
}
parameters {
string(name: 'Репозиторий', defaultValue: 'MyRepos', description: '''Укажите репозиторий в Гитлаб, в него будет выгружен результат (если репозиторий отсутствует в Гитлаб, то он будет создан)''')
string(name: 'Ветка', defaultValue: 'Vendor1C', description: '''Укажите ветку, в которую будут отправлены релизы (по умолчанию будет использована ветка Vendor1C)''')
choice(name: 'Формат', choices: ['EDT', 'XML'], description: '''Выберите формат, в который будут преобразованы исходники конфигурации базы 1С''')
string(name: 'Платформа 1С', defaultValue: '8.3.25.1394', description: '''Укажите версию платформы 1С. Если указанная версия платформы не установлена на сервере – получим ошибку''')
string(name: 'Версия EDT', defaultValue: '2024.2.3', description: '''Укажите версию EDT. Если указанная версия EDT не установлена на сервере – получим ошибку ''')
string(name: 'Папка с релизами', defaultValue: '\\\\server\\Install\\1C\\Релизы\\83\\ERP Управление предприятием', description: Версия релиза должна совпадать с названием каталога, а внутри должен быть файл 1cv8.cf.''')
text(name: 'Релизы', defaultValue: '2.5.20.75', description: '''Введите версии релизов 1С - через запятую или каждый релиз в новой строке. (например: 8.3.20.75, 8.3.20.91, 8.3.20.101)''')
}
environment {
fileserver = '192.168.ххх.ххх'
// vPlatform = '8.3.25.1394'
// EDTversion = '2024.2.3'
YA_MESSENDGER = credentials('Y_Messenger_token')
}
stages {
stage('Подготовка релиза') {
steps {
script {
def processedVersions = []
def versions = params["Релизы"].split(/[\s,]+/)
versions = versions.findAll { it != null && !it.isEmpty() }
if (versions.size() == 0) {
currentBuild.description = "Ошибка: Список версий релизов пуст!"
error "Внимание: Список версий релизов пуст!"
}
bat encoding: 'UTF-8', script: """@echo off
chcp 65001 > nul
type \\\\%server%\\SHARE\\script\\devops
rd /s /q $WORKSPACE\\ > nul 2>&1
exit 0
"""
for (version in versions) {
count++
cf2EDT(version.trim(), params["Репозиторий"], params["Ветка"], params["Формат"], params["Платформа 1С"], params["Версия EDT"], params["Папка с релизами"], count)
processedVersions.add(version.trim())
}
currentBuild.description = "Обработанные версии: " + processedVersions.join(", ")
}
}
}
stage('Отправка репозитория в Gitlab') {
steps {
script {
bat encoding: 'UTF-8', script: """@echo off
chcp 65001
rem set git_name=EDT-update-%DATE:~0,2%%DATE:~3,2%%DATE:~6,4%
echo ---------------------------------
echo Отправка в удаленный репозиторий ${params.Репозиторий}
echo ---------------------------------
git ls-remote git@gitlab:1c/${Repository}.git > nul 2>&1
if %ERRORLEVEL% NEQ 0 (
git remote add origin git@gitlab:1c/${params.Репозиторий}.git
)
git remote -v
echo [INFO] отправка данных в репозиторий
rem git push --mirror origin // затираем репозиторий
git push --all origin
echo [INFO] данные в Gitlab отправлены
"""
}
}
}
}
}
Этот пайплайн включает в себя несколько ключевых этапов:
- Использование скрипта cf2EDT: Все операции по подготовке исходных файлов конфигурации (например, создание временной базы, загрузка файлов .cf, выгрузка в XML) выполняются с помощью скрипта cf2EDT, который использует командную утилиту ibcmd.
- Параметризация пайплайна: Пользователи задают параметры для пайплайна через интерфейс, при этом система автоматически проверяет корректность введенных данных и предупреждает о возможных ошибках (например, отсутствие версии платформы или EDT).
- Конвертация файлов в формат EDT: Получаем из CF конфигурационные файлы, затем они конвертируются в формат EDT с помощью команды -import из командной строки EDT (1C:EDT CLI).
- Автоматическая работа с Git: Если репозиторий с нужным именем отсутствует в GitLab, он создается автоматически, если существует, то изменения добавляются в ветку Vendor1C. Далее скрипт выгружает подготовленные файлы в удаленную ветку "Vendor1C", выполняя все необходимые Git-операции (add, commit, push).
Таким образом, процесс подготовки ветки типовых конфигураций для репозитория были автоматизированы.
3. Что получили
Пайплайн успешно протестирован и внедрен в производство, он активно используется для подготовки обновлений.
На скрине - пример результата работы пайплайна при подготовке ветки "Vendor1C" репозитория с версиями типовой конфигурации 1С:ERP Управление предприятием 2.5.20.75, 2.5.20.91, 2.5.20.101, 2.5.21.99, 2.5.21.106 и 2.5.21.111:
Плюсы от использования пайплайна:
- Экономия времени: автоматизация процесса загрузки и подготовки типовых конфигураций позволила существенно сократить время на выполнение рутинных операций. Подготовка одного релиза конфигурации 1С:ERP УХ с помощью задания Jenkins занимает в 2,5 раза меньше времени, чем выполнение аналогичных операций вручную.
- Уменьшение вероятности ошибок: исключение человеческого фактора при выполнении однотипных операций значительно снизило вероятность ошибок, которые могут происходить при ручной загрузке файлов.
- Повышение эффективности работы специалистов: пайплайн берет на себя все задачи по подготовке и загрузке конфигураций, позволяя специалистам сосредоточиться на более сложных и требующих внимательности задачах, а не на рутинной подготовке веток.