Тримати один модуль на тій версії, що працює
Автооновлення модулів було «все або нічого». writable/auto_update_modules.on
змітав кожен установлений store-модуль, у якого в каталозі є новіша версія, і
єдине, що могло зупинити один із них, — детектор локальних правок, тобто
випадковість, а не рішення. Сайт, який інтегрував один модуль або просто ще не
перевірив його новий реліз, міг утримати його, лише вимкнувши автооновлення для
всього.
Фіксація (pin) — відповідь на рівні модуля: модуль лишається на тій версії, що працює, решта оновлюється далі.
Фіксація — тимчасовий захід, а не спосіб жити. Вона тримає модуль, поки ви
перевіряєте реліз, поки переперевіряється інтеграція або поки клієнт не
підтвердив. Потім її знімають. Модуль, зафіксований на місяці, — це модуль, який
колись оновлять одразу через кілька релізів, а це і є ризиковане оновлення, а не
безпечне. Адмінка і --list завжди показують і зафіксовану версію, і ту, що
пропонує каталог: фіксація може затримати оновлення, але не приховати його.
Що робить фіксація
| Шлях | Коли фіксація діє |
|---|---|
cms9:auto-update (нічний) | пропускає модуль, пише причину в writable/logs/auto-update.log |
cms9:module-update --all | показує модуль як pinned at vX — skipped, код виходу не змінюється |
cms9:module-update <module> | відмовляє, код виходу 1 |
| Кнопка «Оновити» на полиці модулів | заблокована, картка пояснює чому |
| ВЛАСНА кнопка «Оновити» модуля, що оновлює себе сам | заблокована, банер каже зафіксовано vX, доступна vY |
cms9:module-update <module> --ignore-pin | оновлює і переносить фіксацію на нову версію |
Усі ці шляхи проходять одне й те саме рішення в
App\Libraries\UpdateServer\ModuleInstaller::install() — нове місце виклику
успадковує поведінку, а не переписує її. Обидві команди додатково відсікають
зафіксований модуль до будь-якої мережевої роботи, щоб пакетний прогін міг
відзвітувати без завантаження пакета.
Модулі, що оновлюють себе самі
Кілька модулів носять власного клієнта оновлень — Libraries/ModuleUpdater.php
усередині модуля (Notify, Pixozip, CloudStorage). Вони ходять на сервер оновлень
напряму і не проходять через ModuleInstaller, тому питання про фіксацію
ставлять самі, через той самий
App\Libraries\UpdateServer\ModulePins::blockedFor():
check()повертаєpinned,pin_reasonіpin_blockedпоруч ізlatest— і рахує це поза добовим кешем перевірки, щоб фіксація, поставлена п'ять хвилин тому, гасила кнопку зараз, а не завтра;update()відмовляє до завантаження, бекапу й запису — тим самим реченням, що друкує CLI (error: pinned);- власний банер модуля показує зафіксовано vX, доступна vY, а кнопка
«Оновити» —
disabled; реліз із прапорцемsecurity: trueдодає червоний рядок і фіксацію все одно не знімає.
Виклик загорнуто в class_exists() навмисно: ці модулі їдуть окремими пакетами
і ставляться на ядра, старші за саму фіксацію, де класу ModulePins просто
немає. Фіксації там теж не буває — тож «ніщо не блокує» і є правильна відповідь,
а не фатальна помилка.
Пишеш новий модуль із власним апдейтером — скопіюй цю пару викликів. Самооновлювач, що їх не має, — це діра в кожній фіксації на сайті.
Як довести фіксацію, не зрушивши весь сайт
cms9:auto-update має для цього два прапорці:
php spark cms9:auto-update --only=my_module # лише цей модуль; ЯДРО не чіпається
php spark cms9:auto-update --only=my_module --dry-run # вирішує і логує, не пише нічого
--dry-run пише would update 1.0.1 → 1.0.2 — nothing written (і звичний рядок
pinned … skipped для зафіксованого модуля) з позначкою [dry-run] у
writable/logs/auto-update.log. --only і робить перевірку прийнятною на
спільному стенді: без нього довести, що тримається один модуль, означає дати
оновитися всім іншим на цій машині. Приймаються обидві форми: --only=x і
--only x.
Командний рядок
php spark cms9:module-pin my_module --reason="чекаємо підтвердження інтеграції"
php spark cms9:module-pin my_module --version=1.0.3 # зафіксувати не на встановленій версії
php spark cms9:module-unpin my_module
php spark cms9:module-pin --list
php spark cms9:module-pin --list --json
Приймаються обидві форми опцій — --reason=текст і --reason текст.
Коди виходу: 0 — успіх; 1 — некоректний identif модуля, модуль не
встановлений (нема на що фіксувати), модуль їде всередині core-zip (див. нижче)
або — для cms9:module-unpin — модуль не був зафіксований.
Адмінка
На полиці модулів (Модулі → Магазин) установлений модуль отримує:
- Зафіксувати на цій версії — питає причину і заморожує модуль;
- позначку зафіксовано: vX поруч із доступна: vY, коли каталог попереду;
- Зняти фіксацію;
- заблоковану кнопку «Оновити», поки фіксація тримає.
Обидві дії пишуться в журнал адмінки як module.pin / module.unpin разом із
причиною — у фіксації є автор і дата, а не лише запис у файлі.
Де лежить стан
writable/store_pins.json, поруч зі store_versions.json — навмисно поза текою
модуля і поза його рядком у components, щоб фіксація пережила видалення й
повторне встановлення модуля. Так само навмисно це не той самий файл, що
writable/module_local_changes.json: там записано, що випадково зупинив детектор
правок, а тут — що вибрала людина.
{
"my_module": {
"version": "1.0.3",
"by": "owner@example.com",
"at": 1790220000,
"reason": "чекаємо підтвердження інтеграції",
"security": {
"to": "1.0.5",
"since": 1790300000,
"dismissed": ""
}
}
}
version— версія, на якій заморожено модуль;by— e-mail адміна абоcli, якщо фіксували з командного рядка;at— unix-час фіксації (або останнього перенесення через--ignore-pin);reason— вільний текст, видно в адмінці й у--list;security— присутнє, лише поки чекає безпековий реліз, див. нижче.
Файл пишеться атомарно (тимчасовий файл + rename) і видаляється, коли знято
останню фіксацію, — порожній store_pins.json не залишається.
--ignore-pin переносить фіксацію, а не знімає її
php spark cms9:module-update my_module --ignore-pin ставить нову версію і
переписує фіксацію на неї, зберігаючи by і reason. Власник сказав «оновити
саме цей», а не «перестати фіксувати модуль» — зняти фіксацію означало б тихо
повернути модуль у нічний прогін, тобто рівно те, проти чого фіксація й існує.
Щоб справді зняти її — cms9:module-unpin.
Безпекові релізи: фіксація тримає далі
Запис у каталозі може нести необов'язкове булеве поле security у manifest
модуля:
{ "module": "my_module", "version": "1.0.5", "security": true }
update.php (list/check) віддає це поле як є — більше на сервері оновлень
його ніщо не інтерпретує.
Безпековий реліз не знімає фіксацію автоматично. Тихе оновлення — саме те, проти чого фіксація існує. Натомість:
- угорі адмінки зʼявляється червоний банер із назвою модуля і версією, що чекає;
- банер тримається, доки адмін його не закриє, і закриття нічого не оновлює;
- картка модуля позначена так само.
Рішення — оновити зараз чи тримати далі — лишається людині. Звичайні (не безпекові) релізи поводяться так само, тільки без червоного банера.
Межа: модулі, що їдуть у core-zip
Кожен модуль, що їде всередині core-zip, версіонується разом із ядром: оновлювач
ядра кладе його файли як частину білда, а версія — це номер білда ядра. Це
system і standard за Config\ModulePolicy (наприклад notify, gallery) —
два класи, яких пакувальник ніколи не виключає, — плюс будь-який інший модуль,
що є у файловому переліку встановленого білда (платний модуль, у якого ще немає
store-пакета). Вони фіксуються разом із ядром, утриманням білда ядра, а не
поодинці. cms9:module-pin таким відмовляє, і кнопка в адмінці теж (у картки її
просто немає):
notify: Модуль оновлюється разом з ядром, зафіксувати його версію не можна.
Запис фіксації, що лишила на такому модулі старіша версія, фіксацією не є:
оновлювачі й картка його ігнорують, а сам він видаляється з рядком у
writable/logs/auto-update.log.
Коли фіксація — не той інструмент
Фіксація купує час, але не замінює штатну точку розширення. Якщо ви фіксуєте модуль тому, що новий реліз затре ваші правки, проблема — у правках:
- зміни шаблонів → перекриття шаблонів модуля темою;
- зміни поведінки → окремий модуль-надбудова на подіях і точках рендеру;
- правки, вже зроблені у встановленому модулі →
локальні правки в модулі пояснює, як
cms9:module-driftїх знаходить і як патч переносить їх далі.
Перенесіть зміну в одне з цього — і зніміть фіксацію.