В прошлый раз я не успел закончить сборщик, набросав только поверхностную версию для сборки всего модуля целиком. Однако залив его в личном кабинете маркета стало ясно, что работа по данной части еще не закончена. А кроме этого мне надо же еще и обновления для модулей собирать, а это уже чуть более сложная задача. Но обо всем по порядку …
Заливаем модуль, попытка номер раз.
В партнерском кабинете битрикса есть раздел «Маркетплейс 1С-Битрикс», в котором производится работа со всеми вашими модулями.
Интерфейс этот выглядит примерно так:
Добавление модуля сводится к тому, что вам нужно заполнить форму с кучей данных, включая архивчик с полной сборкой модуля. Там надо указать название будущего модуля, описание, цены (если модуль платный), связь с редакциями, категорию, контакты техподдержки, различные флаги для фильтра в маркетплейсе и т.д. Можно даже прицепить свой Google Analytics или метрику, чтобы трэкать просмотры и клики на странице модуля. Заполнив все обязательные поля и отправив форму, сразу стало понятно, что Битрикс — он такой Битрикс везде, даже в партнерском интерфейсе.
После отправки формы из URL пропадает ID модуля, что приводит к невозможности повторной отправки формы без возврата на предыдущую страницу. Точнее, форму то вы отправите, но битрикс сочтет это как попытку создать новый модуль, даже если он уже заведен в системе. Если в таком состоянии отправить форму с файлом сборки модуля, то форма будет отвечать глупой ошибкой:
Архив с решением .last_version не был загружен, либо его структура не соответствует требованиям. Подробную информацию по этой ошибке можно получить в Документации.
И ссылка .. но по ссылке находятся вообще все материалы по маркетплейсам битрикса, и чтобы найти там что-то, то надо изучить все. Благо, я уже изучил заранее, и четко знал, что никакой ошибки у меня точно нет, и битрикс пытается меня надуть. Ну и хорошо хотя бы еще то, что не нужно каждый раз заполнять все поля формы для успешного создания модуля, сам архив тоже не является обязательным для создания решения в админке.
Вторая проблема, с которой я столкнулся — это «Ошибка при распаковке архива». Уж не знаю, что битриксу не понравилось в том архиве, который я собирал с помощью своего сборщика (обычный tar.gz, ничего необычного), но он никак не мог его распаковать. Но я заметил, что если перепаковать архив руками в zip, то он битрикс уже не выдавал ошибки при распаковке. В связи с этим пришлось в сборщике переделать архивацию с tar.gz на zip, что в принципе пофиг.
Ошибки в модуле
После того, как разобрался с архивом, битрикс начал выдавать мне сообщения об ошибках. Видимо, он при заливке модуля сразу же распаковывает его и прогоняет какие-то значимые куски кода через регулярки. Вот что вылезло у меня:
Что?? Версия модуля не указана? Я же её формирую, блин, автоматом, и она 100% есть в архиве, 10 раз проверил. Что не так?… уж было собрался писать в техподдержку, но тут же смекнул, что надо бы представить себя в роли разработчика битрикс. Знаете, таким, новичком, который только месяц познакомился с инфоблоками, а вчера услышал от коллеги про регулярки. После этого, стало ясно, что инструмент написан топорно (как и многое в битриксе), а значит ровно также нужно подходить к генерации файла с версией. Подумав об этом обо всем, а также изучив файлы версий других модулей, удалось выявить такой набор правил:
- для отступов нельзя использовать пробелы, нужно использовать один таб
- нельзя использовать одинарные кавычки для строк, только двойные
- короткий открывающий php тег
- наличие закрывающего php тега
- номер версии должен состоять из трех частей
После того, как подогнал генератор под эти требования, и залил его в маркет, ошибка сразу исчезла, а мое лицо расплылось в улыбке… печальной такой улыбке …
С остальными ошибками все было проще, когда я начал мыслить с позиции битрикс-разработчика. Ошибка «В файле install/index.php не указан $MODULE_ID» говорит нам о том, что нужно указать дефолтное значение этого для поля класса. В моем случае оно формировалось раньше в runtime в конструкторе, но битрикс требует наличия значения сразу.
Ошибка «В файле install/index.php неверно указано имя класса» — вообще как вишенка на торте. Она вылечилась удалением обратного слеша перед указанием CModule в определении класса модуля. Видимо при разработке этого инструментария разработчики не полагались на то, что в php есть неймспейсы.
После устранения всех этих «косяков» и загрузки модуля в zip битрикс схавал архив и больше не ругался.
Теперь, когда модуль залит, становится доступной вкладка «Тестирование». С помощью этого инструмента можно выгрузить залитый модуль на какой-нибудь сайт и провести тестирование там.
Доработка сборщика
Как я уже писал выше, пришлось внести небольшие изменения в плане архивации и создания файла версии в сборщике. Но я решил пойти дальше и полностью переписать инструмент, т.к. теперь я лучше понимаю дальнейшие сценарии его использования.
Совершенно очевидно, что у сборщика есть контекст — версия, которую он собирает. А значит и все команды должны работать в контексте. Я решил вынести в контекст номера последних двух версий, они нужны будут для того, чтобы понять, по какому алгоритму собирать версию. Алгоритма два — один собирает текущую версию полностью, а другой собирает разницу между текущей и предыдущей версией (алгоритм сборки обновления). Для каждого из них я создал входные команды gulp — build_last_version и build_update. Первая команда работает почти также, как я описывал в прошлой статье. Я лишь произвел небольшой рефакторинг, поработал над синтаксисом, исправил мелкие ошибки и изменил формат архива.
Сборка обновления
Для сборки обновления появляется новый таск — diff, который собой заменяет таск move. Задача этого таска — вычислить разницу с помощью git, и положить эту разницу в директорию сборки.
Код у таска простой
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// Перенос последней версии модуля в директорию сборки gulp.task('diff', (callback) => { git.exec({args: `diff ${previousVersion.version} --name-only`}, (error, output) => { if (error) { callback(error); } const globs = extendGlob(output.split(os.EOL)); gulp.src(globs, {base: './'}) .pipe(gulp.dest(path.join(buildFolder, getVersionFolderName()))) .on('end', callback); }); }); |
Тащим diff из гита, получая имена всех файлов. В случае успеха копируем файлы текущего репозитория в директорию сборки, где кладем это все в директорию с номером этой версии. Переменная previousVersion в данном случае берется из контекста (а по сути является глобальной :D), а getVersionFolderName — это функция, которая на основании версий контекста формирует название директории для будущего архива.
Кроме этого сделал небольшой рефакторинг, операцию получения списка версий выделил в промис, т.к. с ним так проще и удобнее работать, а повторяющиеся операции вынес в отдельные функции.
Вот так выглядят задачи build_last_version и build_update после рефакторинга:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
// Сборка текущей версии модуля gulp.task('build_last_version', (callback) => { getTags().then(function(output) { const versions = parseVersions(output); lastVersion = previousVersion = versions[0]; sequence('clean', 'move', 'version', 'encode', 'archive', 'dist', 'clean', callback); }).catch((error) => { console.log(error); }); }); // Сборка обновления модуля (разница между последней и предпоследней версией по тегам git) gulp.task('build_update', (callback) => { getTags().then(function(output) { const versions = parseVersions(output); lastVersion = versions[0]; previousVersion = versions[1]; sequence('clean', 'diff', 'version', 'encode', 'archive', 'dist', 'clean', callback) }).catch((error) => { console.log(error); }); }); |
Ну и осталось создать задачу default, которая будет запускать сразу обе сборки. Нужно это для того, чтобы запустить только команду gulp (или в моем случае npm run gulp) и не вспоминать название команд.
В следующей статье
Наверно, пора подводить первые итоги. Текущую версию модуля я храню на гитхабе. Любой желающий может скачать и установить её себе, пользоваться сколько влезет. Заранее хочу предупредить, что эта версия модуля очень сильно ограничена в функционале. Во-первых, она содержит на данный момент лишь 10% от тех возможностей, которыми я планирую этот модуль снабдить. Во-вторых, единственная на данный момент функция генерации купонов сильно ограничена в скорости (не мной, конечно же, а самим битриксом). Дело в том, что при каждом добавлении купона битрикс выполняет много лишних операций, от которых можно безболезненно избавиться. Каждый, кому это нужно будет, легко сможет снять это ограничение самостоятельно, и тогда купоны будут добавляться в базу очень быстро. Публикацию дальнейших версий модуля в opensource пока не планирую, т.к. сами понимаете …