Опенсорс-расширение 1С на GitHub без боли: ветки под конфигурации, XML вместо EDT и сборка .cfe в одну кнопку
Если вы хоть раз пытались вести «одно расширение на несколько конфигураций» (УНФ/Розница/УТ/КА/ERP) в Git, то знаете три чувства: diff, merge и «почему опять конфликт в Configuration.xml». Мы прошли этот квест на проекте 1C AI Autofill и собрали рабочую схему, которую можно забрать себе.
Дисклеймер: если я говорю «мы», это значит я и мои агенты в Cursor IDE. Они тоже участвуют в мерже — и тоже нервничают, когда конфликтов в Configuration.xml больше, чем изменений в коде.
Что это за проект (в двух строках): расширение для 1С:Предприятие 8.3, которое помогает генерировать продающие описания номенклатуры и (по настройкам) заполнять доп. реквизиты/характеристики с помощью AI. Исходники открыты, релизы лежат на GitHub, а логика разработки — внятная и повторяемая.
Почему опенсорс: изначально это был платный продукт. Со временем коммерческая ценность именно этого кода стала для нас несущественной — поэтому мы решили открыть исходники, чтобы наработки жили дальше и приносили пользу сообществу.
Коротко (TL;DR)
- main — ядро (вся логика и «истина»), а ветки конфигураций — тонкие адаптеры (в основном отличаются
xml/Configuration.xml). - git worktree — чтобы держать одновременно несколько веток рядом и не переключаться туда-сюда.
- Только XML-выгрузка — чтобы diff был читаемым, а merge — предсказуемым.
- Сборка автоматизирована (PowerShell + 1cv8 DESIGNER): из XML → .cfe → загрузка → обновление БД (опционально).
Мем-пауза, чтобы пережить merge

Содержание: Git-схема · Почему XML · Фрагменты кода · Сборка .cfe · Чек-лист · Планы · Как контрибьютить · Что сделать прямо сейчас · Ссылки
0. Для кого статья
- Разработчики 1С, которым нужно поддерживать расширение сразу для нескольких конфигураций.
- Те, кто хочет «как в нормальном мире»: GitHub, релизы, воспроизводимая сборка, минимум ручных действий.
- Те, кто устал от EDT-артефактов и конфликтов, когда «вроде ничего не менял, а изменилось всё».
1. Git «по-взрослому»: одно ядро и несколько веток конфигураций
Фраза «main — это состояние души» смешная ровно до первого релиза. Потом она становится правилом: в main живёт ядро, а ветки конфигураций периодически подтягивают изменения и собирают свои .cfe.
Структура веток
В репозитории держим несколько веток/сборок:
- main — ядро расширения: полная XML-выгрузка (включая
Configuration.xmlиConfigDumpInfo.xml). - UNF_Rozn — сборка для УНФ и Розницы.
- UNF_Rozn_Fresh — сборка для 1cfresh (отличается, в том числе, именем расширения).
- UT_KA_ERP — сборка для УТ, КА и ERP.
Где обычно отличия: в xml/Configuration.xml — имя конфигурации (<Name>) и иногда версия (<Version>). Всё остальное — как в main (если не было осознанного точечного отличия под конкретную конфигурацию).
Worktrees: «хочу видеть всё сразу»
Вместо вечного git checkout — отдельный worktree на каждую ветку. Это резко снижает количество «ой, я правил не там».
git worktree add ../worktrees/UNF_Rozn UNF_Rozn
git worktree add ../worktrees/UT_KA_ERP UT_KA_ERP
Поток разработки (как живём каждый день)
- Фичи и общая логика — делаем в main.
- Ветки конфигураций — периодически делают
git merge main, разрешают конфликты по правилам и выпускают свой релиз. - Редкие исключения: если правка нужна только одной конфигурации — она живёт в её ветке (и вы заранее понимаете, что на следующем merge это может дать конфликт).
Merge main → ветка конфигурации
Команды максимально скучные (а это хорошо):
cd worktrees/UNF_Rozn
git merge main
Конфликты: быстрые правила, чтобы не «вспоминать проект по ходу мержа»
Если Git не знает, кого любить — пусть любит ваши правила:
xml/Configuration.xml: оставляем своё значение<Name>(и при необходимости<Version>) для ветки конфигурации.xml/ConfigDumpInfo.xml: оставляем свою версию/идентификаторы (или разрешаем по смыслу, если менялись осознанно).- Модули, формы, общая логика: почти всегда берём из main (main — источник правды).
Подробно (и тем же смыслом, но в формате «инструкции») это уже оформлено в репозитории: MERGE.md.
2. Почему «чистая XML-выгрузка» выигрывает у EDT в таких репозиториях
EDT мы пробовали. Оно умеет многое, но для сценария «одно ядро → несколько веток конфигураций → частые мержи» цена оказывается слишком высокой.
Что обычно ломает кайф
- Лишние артефакты в репозитории (служебные файлы, метаданные).
- Тяжёлый diff: «как понять, что реально изменилось?»
- Merge как квест: конфликтов больше, чем изменений.
Что делаем вместо
Храним расширение в чистой XML-выгрузке (каталог xml/). В результате:
- diff читается глазами разработчика 1С;
- merge становится процедурой, а не приключением;
- репозиторий остаётся прозрачным (без «а это что за файл?»).
Следы эпохи EDT обычно выглядят так (и да, их лучше игнорировать):
# EDT/Eclipse служебные файлы
.metadata/
.project
.classpath
.settings/
*.launch
3. Как выглядит код: два фрагмента, чтобы было «осязаемо»
Ниже — пара кусочков из расширения: серверный вызов к API и клиентская часть с длительной операцией. Это не «идеальный эталон», а понятный скелет, который работает и хорошо мержится.
Сервер: HTTP + JSON, получение ответа и нормальная ошибка
Функция ОтправитьЗапрос(Промт) Экспорт
СтрокаJSON = СериализоватьЗапросВJSON(Промт);
Соединение = ПолучитьHTTPСоединение();
Запрос = Новый HTTPЗапрос(ПолучитьПутьChatCompletions(), ПолучитьHTTPЗаголовки());
Запрос.УстановитьТелоИзСтроки(СтрокаJSON);
Результат = Соединение.ОтправитьДляОбработки(Запрос); //POST
Если Результат.КодСостояния=200 Тогда
ЧтениеJson = Новый ЧтениеJson;
ЧтениеJson.УстановитьСтроку(Результат.ПолучитьТелоКакСтроку());
РезСтруктура = ПрочитатьJSON(ЧтениеJson);
МассивРезультатов = РезСтруктура["choices"];
Если МассивРезультатов <> Неопределено
И МассивРезультатов.Количество()
И ТипЗнч(МассивРезультатов[0]) = Тип("Структура")
И МассивРезультатов[0]["message"] <> Неопределено
И ТипЗнч(МассивРезультатов[0]["message"]) = Тип("Структура") Тогда
Ответ = СокрЛП(МассивРезультатов[0]["message"]["content"]);
Конецесли;
Иначе
СообщениеобОшибке = "Не удалось получить ответ. Код ошибки: "+Результат.КодСостояния +" "+ Результат.ПолучитьТелоКакСтроку();
ВызватьИсключение СообщениеобОшибке;
КонецЕсли;
Возврат Ответ;
КонецФункции
Функция СериализоватьЗапросВJSON(ТекстЗапроса)
Настройки = НастройкаПоУмолчанию();
Сообщения = Новый Массив;
Сообщение = Новый Структура;
Сообщение.Вставить("role", "user");
Сообщение.Вставить("content", ТекстЗапроса);
Сообщения.Добавить(Сообщение);
Структура = Новый Структура;
Модель = Настройки.МодельИИ;
Если НЕ ЗначениеЗаполнено(Модель) Тогда
Модель = "auto";
КонецЕсли;
Структура.Вставить("model", Модель);
Структура.Вставить("messages", Сообщения);
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON,Структура);
Возврат ЗаписьJSON.Закрыть();
КонецФункции
Клиент: длительная операция, чтобы форма не зависала
Когда пользователь нажимает «Заполнить ИИ», запрос может выполняться заметно долго. Поэтому — длительная операция: запускаем на сервере и ждём с окном ожидания.
&НаКлиенте
Процедура GPT_ЗаполнитьОписание(Команда)
СостояниеНастроек = GPT_ОбщийВызовСервера.GPT_СостояниеНастроек();
Если НЕ СостояниеНастроек.Готово Тогда
ОткрытьФорму("ОбщаяФорма.GPT_Регистрация", , ЭтотОбъект, , , , , РежимОткрытияОкнаФормы.БлокироватьОкноВладельца);
Возврат;
КонецЕсли;
GPT_ОтправитьЗапросНаСервере();
ОписаниеОповещения = Новый ОписаниеОповещения("ПолучениеОтветаChatGPT", ЭтотОбъект);
ПараметрыОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(ЭтотОбъект);
ПараметрыОжидания.ВыводитьОкноОжидания = Истина;
ДлительныеОперацииКлиент.ОжидатьЗавершение(ЭтаФорма.GPT_ДлительнаяОперация, ОписаниеОповещения, ПараметрыОжидания);
КонецПроцедуры
&НаСервере
Функция GPT_ОтправитьЗапросНаСервере()
ПараметрыВыполнения = ДлительныеОперации.ПараметрыВыполненияФункции(Новый УникальныйИдентификатор);
ПараметрыВыполнения.ОжидатьЗавершение = Ложь;
ЭтаФорма.GPT_ДлительнаяОперация = ДлительныеОперации.ВыполнитьФункцию(
ПараметрыВыполнения,
"GPT_ОбщийМодульСервер.СгенерироватьОписаниеИДопСвойстваНоменклатуры",
Объект.Ссылка
);
КонецФункции
4. Автоматизация сборки: .cfe без рутины «LoadCfg / UpdateDBCfg вручную»
Ручная сборка .cfe — это десятки одинаковых действий, умноженные на количество веток. Автоматизация убирает человеческий фактор: скрипт делает всё одинаково каждый раз.
Типовая схема: main → merge в ветки → скрипт собирает .cfe для каждой ветки → (опционально) можно повесить на CI.
Пример скрипта (PowerShell): параметры
Смысл простой: путь к платформе, строка подключения, путь к XML, куда положить .cfe, имя расширения и флаги.
param(
[string]$PlatformExe = 'C:\Program Files\1cv8\8.5.1.1150\bin\1cv8.exe',
[string]$ConnectionString = '',
[string]$XmlPath = (Join-Path (Split-Path $PSScriptRoot -Parent) 'xml'),
[string]$ExtensionCfePath = (Join-Path (Split-Path $PSScriptRoot -Parent) 'bin\Расширение.cfe'),
[string]$ExtensionName = 'GPT_ОписаниеНоменклатуры',
[switch]$BuildFromXml,
[switch]$SkipLoadExtension,
[switch]$SkipDbUpdate,
[switch]$SkipRunClient,
[switch]$Wait
)
Сборка .cfe из XML: два вызова DESIGNER
# Сборка .cfe из xml (если -BuildFromXml)
if ($BuildFromXml) {
$xmlFullPath = [System.IO.Path]::GetFullPath($XmlPath)
$loadXmlArgs = $baseArgs + @('/LoadConfigFromFiles', $xmlFullPath, '-Extension', $ExtensionName)
Invoke-Platform -Arguments $loadXmlArgs -OperationName 'Сборка: загрузка расширения из XML в конфигурацию'
$dumpArgs = $baseArgs + @('/DumpCfg', $cfeFullPath, '-Extension', $ExtensionName)
Invoke-Platform -Arguments $dumpArgs -OperationName 'Сборка: выгрузка расширения в .cfe'
}
Загрузка .cfe и обновление БД (если нужно)
$loadArgs = $baseArgs + @('/LoadCfg', $cfeFullPath, '-Extension', $ExtensionName)
Invoke-Platform -Arguments $loadArgs -OperationName 'Загрузка расширения из .cfe в конфигурацию'
$updateArgs = $baseArgs + @('/UpdateDBCfg', '-Extension', $ExtensionName)
Invoke-Platform -Arguments $updateArgs -OperationName 'Обновление конфигурации БД'
Полный цикл одной командой обычно выглядит так: .\update-extension-and-run-db.ps1 -BuildFromXml. Скрипт соберёт, загрузит, обновит (если не отключено) и может запустить клиент (если предусмотрено вашей обвязкой).
5. Мини-чек-лист релиза (чтобы не держать всё в голове)
- В main: влитые фичи/фиксы, при необходимости обновлён
<Version>вxml/Configuration.xml. - В ветке конфигурации:
git merge main+ конфликты по правилам (имя/версия свои, логика из main). - Сборка: скрипт → получаем .cfe (и при необходимости прогоняем установку в тестовой базе).
- Публикация: релиз в GitHub (отдельно на каждую ветку/сборку).
6. Планы по развитию
Самое очевидное следующее улучшение — автоматизированное тестирование, чтобы релизы не держались на «проверил руками и вроде ок».
- Автотест сборки: воспроизводимая сборка
.cfeизxml/(скриптом) в CI. - Smoke-тест установки: установка/обновление расширения в тестовой базе и проверка, что оно подключилось без ошибок.
- Проверка базовых сценариев: «кнопка есть», «запрос ушёл», «ошибка показывается понятно» (минимум, который ловит регрессии).
7. Как контрибьютить (быстро и без боли)
- Нашли баг / есть идея: создайте issue в репозитории — Issues. Если хочется обсудить до реализации — Discussions.
- Хотите сделать PR: начните с CONTRIBUTING.md и посмотрите правила мержа веток в MERGE.md.
- Локальный запуск/сборка: готовый скрипт — automation/update-extension-and-run-db.ps1 (и короткая инструкция — automation/README.md).
Мини-онбординг: форк → ветка/изменения → PR. Если вы делаете правки общей логики — целимся в main; ветки конфигураций подтягивают изменения мерджем.
8. Что можно сделать прямо сейчас (идеи для первого вклада)
- Документация: улучшить разделы «быстрый старт», «частые ошибки», «как собрать .cfe» и «как добавить поддержку новой конфигурации».
- Автотесты/CI: добавить workflow, который собирает
.cfeизxml/, а также smoke-проверки установки/обновления в тестовой базе. - Улучшение DX: сделать понятнее сообщения об ошибках (HTTP/JSON/настройки), добавить диагностический режим/логирование (без лишнего шума).
- UI/UX в формах: мелкие улучшения размещения команд/кнопок/подсказок, чтобы пользователю было проще начать.
- Быстрые задачи: берите подборку good first issue и help wanted.
Ссылки
- Репозиторий: msrv-tech/1c-ai-autofill
- Релизы (.cfe): GitHub Releases
Заключение
Опенсорс на 1С — это не «страшно и больно», если у вас предсказуемая структура: main как ядро, ветки как сборки, чистая XML-выгрузка и скрипт сборки. Остальное — дисциплина и пару раз пережить первый merge.
Вступайте в нашу телеграмм-группу Инфостарт
