1
0
mirror of https://github.com/Bayselonarrend/OpenIntegrations.git synced 2026-04-26 20:43:22 +02:00
Files
OpenIntegrations/CONTRIBUTING.md
T

312 lines
32 KiB
Markdown

# 🤗 Участникам
Привет и спасибо, что нашли время для участия в развитии Открытого пакета интеграций! В этом документе приведены основные положения и особенности разработки, знание которых поможет избежать недопониманий и добиться более конструктивной коммуникации в рамках данного проекта
## Основное
Сразу стоит отметить, что OpenIntegrations имеет явный перекос в сторону авторского проекта, нежели правильного настоящего open-source, где участие максимально широкого круга людей является целью, приветствуется и строго регламентировано. На практике это, в первую очередь, означает ограничение круга задач, которые могут быть взяты вами за основу своего вклада в данный репозиторий:
<br>
🟢 **Исправление ошибок и доработка существующих модулей** <br>
Если вы нашли ошибку в существующем функционале и хотите ее исправить - это всегда приветствуется. Способ исправления (и уточнение, что это действительно ошибка), конечно, лучше все равно обсудить в Issues, но, так или иначе, это тот вид участия, который максимально прост и обычно не требует лишнего погружения во все тонкости проекта
🟡 **Добавление новых функций в существующие модули** <br/>
Это куда более сложный, но допустимый способ участия. Техническая сторона его реализации будет описана в следующем разделе. Тут важно отметить только то, что добавление нового функционала обязательно влечет за собой дискуссию о его целесообразности и поддерживаемости. Не спешите реализовывать и делать PR - сделайте сначала Issues
🔴 **Добавление нового модуля** <br/>
Это практически нереалистичный сценарий. Как уже было сказано выше, OpenIntegrations - по большей части авторский проект, просто с открытым кодом. Это обусловлено во многом спецификой 1Сного open-source, да и open-source в целом: участников мало, они приходят и уходят, не несут никакой ответственности за свой вклад и имеют право не участвовать в проекте как только им это станет не интересно. В этом нет ничего странного или неправильного, но приводит к тому, что любой модуль, целиком или в основе, реализованный сторонним разработчиком, становится в конце концов мертвым грузом. Я бы хотел избежать такого сценария. Если у вас есть идея (или даже наработки) в части какой-либо новой технологии, то вы можете либо реализовать ее самостоятельно в рамках отдельного проекта, используя инструментарий Открытого проекта интеграций, либо написать Issues и, возможно, однажды заготовка этого модуля появится в пакете. Тогда вы сможете там поучаствовать
> [!IMPORTANT]
> Также, вне зависимости от желаемого вида участия, я буду очень благодарен, если это участие начнется не с PR, а с Issues. Отказ участнику - это всегда неприятно для обеих сторон, но он неизбежно последует, если предлагаемые изменения не к месту (по моему эгоистичному мнению) или выполнены некорректно с технической части. Велик шанс, что вы просто потратите свое время в пустую
## Техническая часть
В отличии от сути вносимых изменений, где каждый случай уникален и требует обсуждения, техническая их реализация достаточно сильно регламентирована и практически не терпит отхода в сторону от генеральной линии. Обусловлено это автоматизацией различных процессов, будь то создание документации, тестирование, перевод на английский язык или подготовка релизов. Эти процессы просто не работают для функций и модулей, реализованных без учета установленных стандартов
Разработка проекта ведется в ветке `main`, исключительно в русской версии пакета для 1С:Предприятие формата [EDT](https://openintegrations.dev/docs/Start/Build-from-source). Исходный код данной версии находится в `src/ru/OPI`. Никакие друге части исходного кода не подлежат изменению: версия для OneScript, CLI, а также все варианты английской ветки проекта, являются продуктом автоматизированного преобразования из оригинала и теряют все ручные изменения при очередном цикле CI
Если ваша доработка является исправлением ошибки, то никаких других особенных условий к ней не применяется. Добавление же новых функций, в свою очередь, сопряжено еще с рядом дополнительных регламентов, которые должны быть соблюдены. В частности, любую добавляемую функцию в Открытом пакете интеграций условно можно разделить на 4 части, каждая из которых должна присутствовать в вашей реализации:
### Тело функции
Непосредственно реализуемый функционал. Важной частью любой функции является система приведения типов, которая преобразует входные параметры в ожидаемые. В частности, она жизненно необходима для CLI-версии проекта (с той же кодовой базой, преобразуется из 1С), где входные параметры определяются вводом в консоль и всегда на входе являются только Строками. Ознакомится со всеми видами процедур приведения типов можно в модуле `OPI_ПреобразованиеТипов`. Однако, проще всего посмотреть в другие функции модуля, изменения для которого вы реализуете - там всегда будут готовые примеры правильного приведения типов, которые можно перенять:
```bsl
// Пример из модуля Bitrix24
Функция СоздатьЗависимостьЗадач(Знач URL, Знач IDИсточника, Знач IDПриемника, Знач ТипСвязи, Знач Токен = "") Экспорт
// Явное приведение типа через процедуру модуля OPI_ПреобразованиеТипов
OPI_ПреобразованиеТипов.ПолучитьСтроку(ТипСвязи);
Параметры = НормализоватьАвторизацию(URL, Токен, "task.dependence.add");
// Неявные приведения типов при использовании функции ДобавитьПоле()
// Третий параметр описывает тип данных, процедуры OPI_ПреобразованиеТипов используются внутри
OPI_Инструменты.ДобавитьПоле("taskIdFrom", IDИсточника, "Строка", Параметры);
OPI_Инструменты.ДобавитьПоле("taskIdTo" , IDПриемника, "Строка", Параметры);
OPI_Инструменты.ДобавитьПоле("linkType" , ТипСвязи , "Строка", Параметры);
Ответ = OPI_ЗапросыHTTP.PostСТелом(URL, Параметры);
Возврат Ответ;
КонецФункции
```
В качестве возвращаемого значения функции разрешено использовать только значения, сериализуемые в JSON (т.е.имеющие тип Строка, Число, Булево, Дата, Массив, Структура, Соответствие), а также значения с типом ДвоичныеДанные. В редких случаях может возвращаться объект Native API компоненты. Использовать данные других типов для возвращаемого значения, а также в качестве элементов коллекции, являющейся возвращаемым значением, запрещено
Также, при описании сигнатуры функции в ОПИ, принято использовать ключевое слово `Знач` для всех параметров. Экспортные функции основного интерфейса библиотеки не должны изменять передаваемые параметры внутри себя - это объект контроля разработчика внутри прикладной логики. Ключевое слово же является скорее маркером, указывающим внешнему пользователю на соблюдение этого правила
Если подытожить, то основное правило при разработке новых функций в существующем модуле можно сформулировать так:
> [!NOTE]
> Посмотри на остальные и сделай единообразно
### Документирующий комментарий
Документирующий комментарий - обязательная и важнейшая часть любой создаваемой функции. На его основе формируется онлайн-документация и CLI-версия. По сути своей, документирующий комментарий в ОПИ - это стандартный комментарий EDT, который можно создать, кликнув правой кнопкой мыши на имени функции и выбрав пункт `Источник -> Генерировать комментарий к методу`. Однако, есть и несколько дополнительных особенностей:
1. Первая строка всегда является синонимом функции, а вторая - ее кратким (в одну строку) описанием
```bsl
// Выполнить команду
// Выполняет команду по ее описанию
//
// Параметры:
// Соединение - Строка, Произвольный - Соединение или строка подключения - dbc
...
```
2. У всех параметров в комментарии должен быть четвертый блок - имя опции для CLI. Он должен представлять из себя короткое слово (полное или сокращенное) латинскими буквами. Оно будет использовано для указания параметра в консольной версии ОПИ. На примере это слово `access`:
```bsl
// Получить информацию об аккаунте
// Получает информацию об аккаунте
//
// Параметры:
// ПараметрыДоступа - Структура Из КлючИЗначение - Параметры доступа - access
//
// Возвращаемое значение:
// Соответствие Из КлючИЗначение - сериализованный JSON ответа от Green API
Функция ПолучитьИнформациюОбАккаунте(Знач ПараметрыДоступа) Экспорт
```
3. В блоке `Параметры` нельзя использовать знак `-` кроме как для разделения групп. Это ломает парсер, разбирающий комментарии в онлайн-документацию. Обычно, вместо него подходит просто пробел или символ `>`:
```bsl
// Получить структуру фильтра задач
// Возвращает структуру полей для фильтрации задач в методе ПолучитьСписокЗадач
//
// Параметры:
// Пустая - Булево - Истина > структура с пустыми значениями, Ложь > в значениях будут описания полей - empty
// КакСоответствие - Булево - Истина > возвращает поля фильтра как соответствие - map
//
// Возвращаемое значение:
// Структура Из КлючИЗначение - Структура полей
Функция ПолучитьСтруктуруФильтраЗадач(Знач Пустая = Ложь, Знач КакСоответствие = Ложь) Экспорт
```
4. Между блоком с кратким описанием и блоком `Параметры`, при необходимости, может быть вставлен блок `Примечание`. Там можно указать особенности работы с функцией и/или ссылку на оригинальную документацию сервиса (технологии). При указании ссылки, `https://` должен быть заменен на `@`
```bsl
// Получить список пользовательских полей задачи
// Получает список пользовательских полей для задач
//
// Примечание:
// Метод в документации API: [task.item.userfield.getlist](@dev.1c-bitrix.ru/rest_help/tasks/task/userfield/getlist.php)
//
// Параметры:
// URL - Строка - URL внешнего вебхука или адрес Bitrix24 при использовании токена - url
// Токен - Строка - Токен авторизации, если используется не вебхук - token
//
// Возвращаемое значение:
// Соответствие Из КлючИЗначение - сериализованный JSON ответа от Bitrxi24
Функция ПолучитьСписокПользовательскихПолейЗадачи(Знач URL, Знач Токен = "") Экспорт
```
5. Указание полей коллекций через `*` не используется. При указании типов параметров `Структура` или `Соответствие`, достаточно указать `Структура Из КлючИЗначение` или `Соответствие Из КлючИЗначение`. Для параметров с типом `Массив` используется `Массив Из <Тип данных>` или `Массив Из Произвольный`, если типов несколько (в таком случае стоит подробнее разъяснить это в блоке описания параметра). В общем случае, описания одного параметра и описания возвращаемого значения не должны занимать больше одной строки
```bsl
// Выполнить команду
// Выполняет команду по ее описанию
//
// Параметры:
// Соединение - Строка, Произвольный - Соединение или строка подключения - dbc
// Команда - Строка - Имя команды для выполнения - comm
// Аргумент - Произвольный - Аргумент команды - arg
// База - Строка - База данных, в которой необходимо провести операцию - db
// Данные - Структура Из КлючИЗначение - Основные поля данных для выполнения операции - data
//
// Возвращаемое значение:
// Соответствие Из КлючИЗначение - Результат выполнения операции
```
### Unit-тест
Каждая функция должна быть покрыта Unit-тестом - это важнейшая часть поддержки библиотек на длинной дистанции, позволяющая выпускать каждый новый релиз, не задаваясь вопросом "Работают ли созданные ранее функции до сих пор или уже нет?"
> [!IMPORTANT]
> Сразу стоит оговорится: далее пойдет достаточно запутанное, если не сказать душное, описание регламента создания тестов. При этом, вы не сможете запустить созданные тесты самостоятельно, чтобы проверить их работоспособность. Поэтому их создание находится в категории "Сделайте как-нибудь": частичное несоответствие добавленных тестов регламенту не будут причиной для отклонения PR. Я буду рад, если вы добавите их хотя бы в каком-то виде и в правильном модуле, а мне будет достаточно привести их к корректному виду, а не писать целиком с нуля. Также тут продолжает работать правило из блока разработки функций: *"Посмотри на остальные и сделай единообразно"*
Все Unit-тесты находятся в модуле `OPI_Тесты`, в области `СлужебныеПроцедурыИФункции -> АтомарныеТесты -> Имя модуля без префикса`, и представляют из себя процедуру, название которой состоит из имени модуля (без префикса `OPI_`), нижнего подчеркивания и имени тестируемой функции
```bsl
#Область АтомарныеТесты
#Область Telegram
Процедура Telegram_ПолучитьИнформациюБота(ПараметрыФункции)
Токен = ПараметрыФункции["Telegram_Token"];
Результат = OPI_Telegram.ПолучитьИнформациюБота(Токен);
// END
Обработать(Результат, "Telegram", "ПолучитьИнформациюБота");
КонецПроцедуры
```
Процедура всегда должна содержать один или несколько вызовов функции `Обработать`, в которую передается результат выполнения, имя библиотеки и имя тестируемой функции. При желании реализовать несколько проверок в рамках одного теста, можно в качестве четвертого параметра указать строкой `Вариант`. Эти данные будут переданы в функцию проверки результата теста, о которой пойдет речь в следующем разделе
> [!IMPORTANT]
> Для основного результата теста `Вариант` должен быть не указан
```bsl
...
// END
Обработать(Результат, "PostgreSQL", "СоздатьТаблицу");
Таблица = "АБВ ГДЕ";
Результат = OPI_PostgreSQL.СоздатьТаблицу(Таблица, СтруктураКолонок, СтрокаПодключения, НастройкиTLS);
Обработать(Результат, "PostgreSQL", "СоздатьТаблицу", "Ошибка имени");
Таблица = "somename";
СтруктураКолонок.Вставить("wtf_field", "WTF");
Результат = OPI_PostgreSQL.СоздатьТаблицу(Таблица, СтруктураКолонок, СтрокаПодключения, НастройкиTLS);
Обработать(Результат, "PostgreSQL", "СоздатьТаблицу", "Ошибка типа");
```
Также, в теле тестовой процедуры используются служебные комментарии `// SKIP` и `// END`. Они отслеживаются парсером при создании онлайн-документации: тестовая процедура является там наглядным примером кода для пользователя. При помощи данных служебных комментариев можно отсечь лишние строки, которые нужны в тесте, но не нужны в примере кода.
```bsl
...
// Тут идет удаление таблицы перед тестом создания, чтобы не получить ошибку "уже существует"
// Но в примере работы с функцией СоздатьТаблицу для документации это не нужно показывать
OPI_PostgreSQL.УдалитьТаблицу(Таблица, СтрокаПодключения, НастройкиTLS); // SKIP
Результат = OPI_PostgreSQL.СоздатьТаблицу(Таблица, СтруктураКолонок, СтрокаПодключения, НастройкиTLS);
// END
// Весь код после END не попадает в документацию
Обработать(Результат, "PostgreSQL", "СоздатьТаблицу");
```
Сама тестовая процедура всегда принимает один параметр - `ПараметрыФункции`. Несколько атомарных тестов объединяются по смыслу (чаще всего - по области в основном модуле библиотеки) в тестовые наборы. Тестовые наборы создаются также в модуле `OPI_Тесты`, в области `СлужебныйПрограммныйИнтерфейс -> ЗапускаемыеТесты -> Имя модуля без префикса`. Каждый тест должен принадлежать тестовому набору, там определяются и `ПараметрыФункции`
```bsl
#Область ЗапускаемыеТесты
#Область Ollama
Процедура OLLM_ОбработкаЗапросов() Экспорт
ПараметрыТеста = Новый Структура;
OPI_ПолучениеДанныхТестов.ПараметрВКоллекцию("Ollama_URL" , ПараметрыТеста);
OPI_ПолучениеДанныхТестов.ПараметрВКоллекцию("Ollama_Token", ПараметрыТеста);
Ollama_СкачатьМодель(ПараметрыТеста);
Ollama_ПолучитьВерсию(ПараметрыТеста);
Ollama_ПолучитьОтвет(ПараметрыТеста);
Ollama_ПолучитьОтветВКонтексте(ПараметрыТеста);
Ollama_ПолучитьПредставления(ПараметрыТеста);
Ollama_ПолучитьСтруктуруПараметровЗапроса(ПараметрыТеста);
Ollama_ПолучитьСтруктуруПараметровВКонтексте(ПараметрыТеста);
Ollama_ПолучитьСтруктуруСообщенияКонтекста(ПараметрыТеста);
Ollama_ПолучитьСтруктуруПараметровПредставлений(ПараметрыТеста);
КонецПроцедуры
```
В тестовом наборе определяются параметры, передаваемые в тесты всего набора:
```
ПараметрыТеста = Новый Структура;
OPI_ПолучениеДанныхТестов.ПараметрВКоллекцию("Ollama_URL" , ПараметрыТеста);
OPI_ПолучениеДанныхТестов.ПараметрВКоллекцию("Ollama_Token", ПараметрыТеста);
```
Они добавляются в коллекцию при помощи специальной функции `OPI_ПолучениеДанныхТестов.ПараметрВКоллекцию` и характеризуются идентификаторами, вроде `Ollama_URL`. На практике, это ключи JSON файла с секретными и не секретными данными для тестирования. Вам не будет доступен этот файл, поэтому вы можете не сильно заморачиваться над используемыми именами: можно найти уже существующие в тестовом наборе, если они подходят вам по смыслу (по аналогии с существующими тестами), или придумать новые, описав в PR, что они означают.
### Проверки тестов
Как уже было сказано ранее, каждый Unit-тест должен содержать вызов функции `Обработать`. Эта функция передает значение результата теста и его варианта в соответствующую процедуру проверки, которая должна располагаться в модуле `OPI_ПолучениеДанныхТестов`, в области `СлужебныеПроцедурыИФункции -> Проверки` и иметь имя, равное имени процедуры теста, но с префиксом `Проверка_`, Например `Проверка_Telegram_ОтправитьТекстовоеСообщение`
В этой процедуре можно использовать утверждения для анализа корректности переданного результата при помощи конструкции `ОжидаетЧто(Значение1).Равно(Значение2)`, а также ветвить проверки в зависимости от переданного значения в параметр `Вариант`. Процедура проверки должна иметь 2 обязательных параметра (`Результат` и `Вариант`), а также до трех нестандартных параметров, которые могут быть переданы из теста при вызове функции `Обработать`, после параметра `Вариант`
```bsl
// Простой вариант вызова из теста: Вариант = Неопределено, доп. параметры не передаются
Обработать(Результат, "Telegram", "ОтправитьТекстовоеСообщение");
// Комплексный вариант вызова из теста: Вариант = "Канал", два доп. параметра
Обработать(Результат, "Telegram", "ОтправитьТекстовоеСообщение", "Канал", ПараметрыФункции, Текст);
...
Функция Проверка_Telegram_ОтправитьТекстовоеСообщение(Знач Результат, Знач Вариант, Параметры = "", Текст = "")
ОжидаетЧто(Результат).ИмеетТип("Соответствие").Заполнено();
ОжидаетЧто(Результат["ok"]).Равно(Истина);
Если Не ЗначениеЗаполнено(Вариант) Тогда
ИмяПараметра = "Telegram_MessageID";
ОжидаетЧто(Результат["result"]["text"]).Равно(Текст);
ИначеЕсли Вариант = "Канал" Тогда
ИмяПараметра = "Telegram_ChannelMessageID";
ОжидаетЧто(Результат["result"]["text"]).Равно(Текст);
Иначе
ИмяПараметра = "";
КонецЕсли;
Если ЗначениеЗаполнено(ИмяПараметра) Тогда
IDСообщения = OPI_Инструменты.ЧислоВСтроку(Результат["result"]["message_id"]);
// Запись нового параметра теста в JSON
ЗаписатьПараметр(ИмяПараметра, IDСообщения);
OPI_Инструменты.ДобавитьПоле(ИмяПараметра, IDСообщения, "Строка", Параметры);
КонецЕсли;
Возврат Результат;
КонецФункции
```
При ложности какого-либо из утверждений тест будет считаться проваленным, что позволит узнать об изменении внешнего API или поломке при изменении общих функций библиотеки
В целом, это все условия, которые должны быть соблюдены для успешного принятия вашего запроса на слияние. Удачи и хорошего коддинга!
*Данный документ может быть дополнен или изменен в будущем. Спасибо за прочтение!*