Сборка и публикация
Эта страница проведёт вас от дополнения, которое работает на вашей машине, до дополнения, которое владельцы серверов могут установить. Вы сделаете одну релизную сборку, узнаете, как версии выбираются за вас, и опубликуете в официальном маркетплейсе Pano на panomc.com — бесплатно или (с небольшой дополнительной связкой) как платное дополнение.
«Публикация» здесь означает превращение вашего дополнения в релизный jar (.jar — единственный zip-подобный файл, содержащий всё ваше скомпилированное дополнение) и размещение его там, где другие могут его получить.
Примеры на этой странице используют дополнение Shoutbox из Начала работы — небольшое дополнение, чей plugin ID — pano-plugin-shoutbox. Везде, где вы видите shoutbox или pano-plugin-shoutbox, подставляйте pluginId вашего собственного дополнения.
Если вы ещё не собрали своё дополнение, начните с Начала работы и Разработки бэкенда.
Прежде чем начать
Приготовьте эти четыре вещи. Остальная часть страницы предполагает их:
- Ваше дополнение уже собирается локально — выполнение
./gradlew buildв папке вашего дополнения завершается без ошибок. Если нет, сначала вернитесь к Началу работы и Разработке бэкенда. - Код вашего дополнения живёт в репозитории GitHub.
- GitHub Actions включён для этого репозитория (для новых репозиториев он включён по умолчанию).
- У вас есть бесплатный аккаунт на panomc.com.
Чек-лист первого релиза
Остальная часть страницы объясняет каждую часть детально, но вот вся работа по порядку, чтобы вы всегда знали, что осталось. Каждый шаг ссылается на своё полное объяснение и заканчивается тем, как понять, что он сработал.
Большая часть работы — одноразовая настройка (шаги 2–6). После этого каждый будущий релиз — просто шаг 7 — закоммитить и запушить.
- Соберите один раз локально, чтобы подтвердить, что jar производится. → Релизная сборка. Готово, когда вы видите
BUILD SUCCESSFULи jar вbuild/libs/. - Создайте ресурс в маркетплейсе на panomc.com. → Создание ресурса. Готово, когда у вашего дополнения есть страница на panomc.com с пустым списком версий.
- Создайте API-токен и сохраните его как секрет репозитория с именем
PANO_PROD_TOKEN(для веткиmain). → Создание API-токена. Готово, когда секрет перечислен в настройках вашего репозитория. - Создайте секрет
TOKEN_GITHUB(GitHub Personal Access Token). Пропустите это, и каждый релиз падает на самом первом шаге. → Обязательно: секретTOKEN_GITHUB. - Добавьте
.releaserc.jsonс плагином публикации Pano и замените плейсхолдеры в нём. → Разбор.releaserc.json. - Добавьте один шаг установки в workflow, в оба job-а, чтобы плагин публикации Pano был доступен. Пропустите это, и релиз падает с
Cannot find module @PanoMC/semantic-release-pano. → Плагин Pano должен быть установлен в workflow. - Закоммитьте с сообщением в формате conventional-commit и запушьте в
main. → Запушьте и наблюдайте публикацию. Готово, когда запуск Actions показывает зелёную галочку, а новая версия появляется в вашем ресурсе.
Релизная сборка
Релизная сборка компилирует ваш бэкенд Kotlin и собирает и встраивает Svelte UI в jar (.jar — единственный самодостаточный файл, который вы отгружаете). Это обычный:
./gradlew buildЗапускайте это из корневой папки вашего дополнения. Gradle — инструмент сборки для Kotlin-стороны — считайте ./gradlew build эквивалентом npm run build из мира JVM, а ./gradlew («обёртку Gradle») — скриптом в вашем проекте, который запускает правильную версию Gradle за вас. Через минуту-две вы должны увидеть BUILD SUCCESSFUL.
Вывод приземляется в:
build/libs/pano-plugin-shoutbox-<version>.jarЛокально <version> всегда local-build (так что файл — pano-plugin-shoutbox-local-build.jar). Теперь вы должны увидеть этот файл внутри build/libs/. Реальные номера версий приходят из CI — CI (continuous integration) — автоматическая сборка, которую GitHub запускает на своих серверах каждый раз, когда вы пушите. Смотрите Версионирование ниже.
Релизным jar нужен UI
Для релиза всегда запускайте обычный ./gradlew build — никогда не добавляйте -Pnoui. Флаг -Pnoui пропускает сборку UI Bun/rollup, и это может отгрузить сломанное дополнение двумя разными способами:
- Если вы никогда не собирали UI: jar отгружается без UI вообще — ваше дополнение загружается без экранов панели или темы.
- Если старая полная сборка оставила
plugin-ui.zip: jar незаметно впекает этот устаревший UI, так что вы отгружаете устаревший интерфейс, не замечая.
Если хотите быть уверены, что старый UI zip не переиспользуется, запустите ./gradlew clean build (задача clean сначала удаляет предыдущий вывод сборки). -Pnoui только для быстрого цикла разработки только бэкенда (смотрите Начало работы).
jar полностью самодостаточен: бэкенд Kotlin, встроенный бандл UI, локализации и logo.png — всё живёт внутри него. Больше нечего отгружать.
Версионирование
У каждого релиза есть номер версии (вроде 1.0.0), чтобы серверы знали, когда доступно обновление.
Вы не поднимаете версию вручную. Версии решаются из ваших сообщений коммитов, которые должны следовать Conventional Commits — простому формату, где каждый коммит начинается со слова вроде feat: (новая возможность), fix: (исправление бага) или chore: (обслуживание). Эти слова управляют и следующим номером версии, и сгенерированным changelog. В версии вроде 1.2.3 1 — major, 2 — minor, а 3 — patch. feat: поднимает minor-версию, fix: поднимает patch-версию, а feat: с футером BREAKING CHANGE: поднимает major-версию.
Четыре разных имени в этом проекте звучат похоже, но означают разное. Эта таблица — та, что стоит держать в порядке:
| Имя | Живёт в | Кто задаёт | Что означает |
|---|---|---|---|
version | gradle.properties | CI, во время релиза | Собственная версия вашего дополнения (вроде 1.1.0). Остаётся local-build в вашей рабочей копии; никогда не редактируйте её вручную. |
pluginPanoVersion | gradle.properties | Вы (оставьте на local-build) | Копируется в манифест jar. CI не трогает его. |
pano-version | манифест jar | приходит прямо из pluginPanoVersion | Просто впечённая копия pluginPanoVersion внутри собранного jar. |
panoVersion | .releaserc.json | Вы | Версия платформы Pano, показываемая в вашем листинге маркетплейса (задаётся в файле конфигурации ниже). |
Не редактируйте версии вручную
Оставьте и version, и pluginPanoVersion в gradle.properties на local-build. Во время релиза CI внедряет реальную version (через -Pversion — способ, которым Gradle принимает значение из командной строки, -Pversion=1.1.0) из вашей истории коммитов. Ручное поднятие её или редактирование тега (git-тега, который semantic-release создаёт для каждого релиза) ломает автоматизацию. CI не внедряет pluginPanoVersion; атрибут манифеста pano-version остаётся local-build. Версия Pano, объявляемая в маркетплейсе, — отдельное значение, задаваемое опцией panoVersion в .releaserc.json (ниже). Пусть ваши сообщения коммитов управляют версией. Смотрите Конфигурацию манифеста для деталей.
Каналы релизов
Boilerplate настроен на два канала релизов, решаемых тем, в какую ветку вы пушите:
| Ветка | Канал | Версия выглядит как |
|---|---|---|
dev | Предрелиз | 1.1.0-dev.3 |
main | Стабильный | 1.1.0 |
Предрелиз — тестовая сборка, которую вы можете попробовать до настоящего релиза. Суффикс -dev.3 означает «3-я dev-сборка на пути к 1.1.0». Владельцы серверов, устанавливающие стабильный канал, никогда их не видят; предрелиз — для вас, чтобы безопасно отрепетировать релиз.
Что такое GitHub Actions (прочтите это сначала)
GitHub Actions запускает скрипты на собственных серверах GitHub всякий раз, когда вы пушите. Скрипт — это YAML-файл в вашем репозитории — здесь .github/workflows/release.yml. Один файл содержит один или несколько job-ов; каждый job — список шагов; шаг выполняет команду или готовое действие. Этот файл делает всё, что ниже: собирает ваш jar и публикует его.
Пуш в dev или main запускает workflow GitHub Actions, поставляемый с pano-boilerplate-plugin в .github/workflows/release.yml. Этот workflow вычисляет следующую версию из ваших коммитов, запускает ./gradlew build (настоящая сборка UI — не -Pnoui), а затем запускает semantic-release — инструмент, который читает ваши сообщения коммитов, решает следующий номер версии, пишет changelog и публикует релиз, всё автоматически.
Одна правка требуется для публикации в маркетплейс. Из коробки workflow boilerplate запускает semantic-release без установленного плагина публикации Pano. Чтобы также публиковать в маркетплейс, вы должны добавить один шаг установки в workflow — это расписано в разделе Плагин Pano должен быть установлен в workflow ниже, и это шаг 6 чек-листа. Помимо этой одной правки и секретов, которые она ожидает, вы не трогаете workflow для обычного дополнения.
Триггер в начале этого workflow — просто:
on:
push:
branches: ['dev', 'main']Это уже в boilerplate — вы его не меняете. Он показан, чтобы вы знали, что пуш в dev или main — весь триггер релиза: нет отдельной кнопки «опубликовать».
Разбор .releaserc.json
.releaserc.json — место, где настраивается semantic-release. Этот файл упоминает API-токен и ресурс маркетплейса, которые вы создаёте в следующем разделе — это нормально. Прочтите этот разбор, чтобы понять файл, настройте его, затем создайте эти вещи после.
Boilerplate поставляет .releaserc.json, который создаёт релиз GitHub с прикреплённым jar. Чтобы также публиковать в маркетплейс, вы добавляете плагин @PanoMC/semantic-release-pano.
Три имени здесь содержат слово «release» — держите их раздельно:
semantic-release— сам инструмент.@semantic-release/commit-analyzer,@semantic-release/release-notes-generator,@semantic-release/github— стандартные, готовые плагины для этого инструмента.@PanoMC/semantic-release-pano— единственный специфичный для Pano плагин, который вы добавляете, делающий публикацию в маркетплейс.
В списке plugins ниже каждая запись — либо имя плагина само по себе, либо пара [name, options] — двухэлементный массив из имени плагина плюс его настройки. Вот полный файл для Shoutbox — адаптированный 1:1 из реальной конфигурации релиза pano-plugin-faq:
{
"branches": [
{ "name": "dev", "prerelease": true },
"main"
],
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
["@semantic-release/github", {
"assets": [
{ "path": "build/libs/*.jar", "label": false },
{ "path": "LICENSE", "label": false }
]
}],
["@PanoMC/semantic-release-pano", {
"file": "build/libs/pano-plugin-shoutbox-${version}.jar",
"panoVersion": "1.0.0",
"useGitHubLink": true,
"repositoryUrl": "https://github.com/YourName/pano-plugin-shoutbox.git",
"configs": [
{
"resourceId": "pano-plugin-shoutbox",
"panoUrl": "https://api-dev.panomc.com",
"tokenVar": "PANO_TOKEN",
"branches": ["dev"]
},
{
"resourceId": "pano-plugin-shoutbox",
"panoUrl": "https://api.panomc.com",
"tokenVar": "PANO_PROD_TOKEN",
"branches": ["main"]
}
]
}]
],
"repositoryUrl": "https://github.com/YourName/pano-plugin-shoutbox.git"
}Замените эти плейсхолдеры
Прежде чем этот файл заработает, замените примерные значения на свои:
YourName(2 места — обе строкиrepositoryUrl) → ваше имя пользователя или организации GitHub.pano-plugin-shoutbox(5 мест — путьfile, оба значенияresourceIdи внутри обеих строкrepositoryUrl) → ваш собственныйpluginId.
Путь file должен содержать ваш pluginId точно, иначе релиз падает намного позже с запутанным «file not found». И да, repositoryUrl появляется дважды намеренно (один раз внутри опций плагина Pano, один раз на верхнем уровне) — задайте URL вашего репозитория в обоих.
Поле за полем:
| Поле | Что оно делает |
|---|---|
commit-analyzer и release-notes-generator | Первые две записи в plugins. Стандартные плагины semantic-release — оставьте их ровно как есть. |
@semantic-release/github assets | Прикрепляет ваш build/libs/*.jar (и LICENSE) к релизу GitHub. Держите плагины в этом порядке — плагин GitHub должен выполниться до плагина Pano, чтобы jar был уже прикреплён, когда useGitHubLink его понадобится. ("label": false просто оставляет собственное имя каждого файла как его метку загрузки — оставьте это.) |
file | Путь к собранному jar. ${version} подставляется версией релиза. |
panoVersion | Версия платформы Pano, под которую собрано и протестировано ваше дополнение (например, 1.0.0) — это значение, показываемое в вашем листинге маркетплейса. Это не собственная версия вашего дополнения. |
useGitHubLink | true = не перезагружать jar; вместо этого указать маркетплейсу на jar, уже прикреплённый к релизу GitHub (плюс его хеш SHA-256 — отпечаток, чтобы загрузку можно было проверить). Идеально для бесплатных дополнений — без дублирующей загрузки. Премиум-дополнения вместо этого загружают jar напрямую (премиум: задайте useGitHubLink: false; смотрите Премиум-аддоны и лицензирование). |
configs[] | Одна запись на канал. Каждая говорит в какой маркетплейс публиковать и с каким токеном, ограничено branches. |
resourceId | Ваш ресурс маркетплейса — для дополнений это ваш pluginId (смотрите ниже). |
panoUrl | API маркетплейса: https://api-dev.panomc.com для канала dev, https://api.panomc.com для main. |
tokenVar | Имя секрета GitHub, содержащего API-токен: PANO_TOKEN для dev, PANO_PROD_TOKEN для продакшена. |
branches | Ограничивает конфигурацию одним каналом, так что пуш в dev никогда не трогает продакшен-маркетплейс (а отсутствующий PANO_PROD_TOKEN не сломает dev-сборку). |
Зачем два configs — и что такое «dev-маркетплейс»
api-dev.panomc.com — отдельный песочный маркетплейс: у него свои ресурсы, свои токены и свой вход, и ничто, что вы там публикуете, никогда не видят реальные владельцы серверов. Разделение по ветке означает, что вы можете отрепетировать релиз на api-dev.panomc.com из вашей ветки dev, затем отгрузить точно тот же код в реальный api.panomc.com из main.
Если вы публикуете своё первое дополнение, держите просто: публикуйте только в main. Удалите запись конфигурации dev (и ветку { "name": "dev", "prerelease": true }), и вам нужен только один токен, PANO_PROD_TOKEN. Добавьте dev-песочницу позже, если когда-нибудь захотите репетиционный канал.
Плагин Pano должен быть установлен в workflow
@PanoMC/semantic-release-pano не опубликован в npm и не является зависимостью boilerplate, так что перечисления его в .releaserc.json недостаточно само по себе — semantic-release упадёт с «Cannot find module @PanoMC/semantic-release-pano».
Это единственная обязательная правка workflow
Вы должны добавить этот шаг установки в оба job-а в .github/workflows/release.yml — job черновой прогонки версии (get-next-version) и job релиза (build-and-release) — размещённый перед шагом semantic-release каждого job-а:
- run: npm install -D git+https://github.com/PanoMC/semantic-release-pano.git(-D = установить как dev-зависимость; URL git+ устанавливает плагин прямо с GitHub, потому что его нет в npm. Этот один шаг использует npm/npx, хотя остальная часть проекта использует Bun — так и должно быть здесь.)
Например, в job-е релиза он идёт прямо перед существующим шагом Release:
# add this line...
- run: npm install -D git+https://github.com/PanoMC/semantic-release-pano.git
# ...before the step already in the file:
- name: Release
env:
GITHUB_TOKEN: ${{ secrets.TOKEN_GITHUB }}
run: npx semantic-release@24.2.6Сделайте то же в job-е черновой прогонки, перед его шагом npx semantic-release --dry-run. Если вы добавите это только в один job, запуск падает на другом с Cannot find module @PanoMC/semantic-release-pano — эта ошибка означает, что вы пропустили один из двух job-ов. Workflow pano-plugin-faq, из которого скопирована эта конфигурация, имеет ровно этот шаг.
Публикация в официальном маркетплейсе Pano
Маркетплейс на panomc.com — место, где владельцы серверов находят и устанавливают дополнения прямо из своей панели. Ресурс — листинг вашего дополнения в магазине на panomc.com. Публикация занимает три шага: создать ресурс, создать API-токен, затем позволить автоматизации загрузить версии. (Секрет TOKEN_GITHUB также требуется — смотрите блок после шага 2.)
1. Создание ресурса
- Зарегистрируйтесь (или войдите) на panomc.com.
- Из области вашего профиля откройте Create Resource и выберите тип Plugin.
- Выберите категорию, заполните название и описание.
- Выберите ценообразование: free или paid. Если вы просто публикуете бесплатное дополнение, выберите free — это вся эта страница. Выбор paid добавляет шаг лицензирования, рассмотренный в Премиум-аддоны и лицензирование.
Теперь вы должны увидеть страницу вашего дополнения на panomc.com с пустым списком версий — автоматизация заполнит его, когда вы запушите.
ID ресурса вашего дополнения — это ваш plugin ID
resourceId вашего дополнения в маркетплейсе — точно ваш pluginId — для Shoutbox это pano-plugin-shoutbox. Именно поэтому configs[] выше используют "resourceId": "pano-plugin-shoutbox", а не случайный ID. (Темы отличаются — они используют случайный UUID — но дополнения нет.) pluginId — единственная идентичность, которую Pano использует везде, где ваше дополнение касается системы: имя директории данных, префикс узла разрешения, сегмент URL для UI и ресурс маркетплейса. Полный список на Конфигурации манифеста.
2. Создание API-токена
- На panomc.com откройте Profile → Settings → API Tokens и нажмите Create.
- Скопируйте токен немедленно — он показывается только один раз, в модальном окне сразу после создания.
- В вашем репозитории GitHub перейдите в Settings → Secrets and variables → Actions и добавьте токен как секрет репозитория (зашифрованное значение, которое могут читать только ваши запуски Actions), с именем, соответствующим вашему
tokenVar:PANO_PROD_TOKENдля каналаmain(продакшен) — тот, что настраивается первым.PANO_TOKENдля каналаdev, только если вы сохранили конфигурацию dev-песочницы. Это другой токен, созданный в отдельной песочницеapi-dev.panomc.com— не то же значение, чтоPANO_PROD_TOKEN.
Страница Settings → Secrets and variables → Actions вашего репозитория теперь должна перечислять PANO_PROD_TOKEN (и PANO_TOKEN тоже, если вы публикуете в dev).
Никогда не коммитьте токен
API-токен даёт права публикации в ваш ресурс. Храните его только как секрет GitHub (или локальную переменную окружения). Никогда не помещайте его в .releaserc.json, коммит или любой файл в репозитории.
Обязательно: секрет TOKEN_GITHUB
Самому релизу GitHub нужен второй секрет, TOKEN_GITHUB, который workflow boilerplate читает (как secrets.TOKEN_GITHUB) в нескольких местах, включая черновую прогонку версии — репетиционный job, который вычисляет следующую версию, ничего не публикуя. Встроенный GITHUB_TOKEN GitHub не доступен под этим именем, так что вы должны создать его сами.
Без этого каждый релиз падает на самом первом шаге
Создайте TOKEN_GITHUB как Personal Access Token (PAT) — токен, который вы генерируете под своим аккаунтом GitHub:
- На GitHub перейдите в свой аватар → Settings → Developer settings → Personal access tokens.
- Создайте classic токен с областью
repo(semantic-release нужна она, чтобы создавать релизы и пушить теги). - Скопируйте его, затем добавьте в вашем репозитории под Settings → Secrets and variables → Actions как секрет с именем ровно
TOKEN_GITHUB.
Список секретов вашего репозитория теперь должен показывать TOKEN_GITHUB.
Предпочитаете встроенный токен GitHub?
Если вы предпочли бы не создавать PAT, вы можете отредактировать workflow, чтобы он читал secrets.GITHUB_TOKEN (автоматический токен GitHub на запуск) вместо secrets.TOKEN_GITHUB. Путь PAT выше — стандартный для boilerplate и не требует правки workflow, так что это рекомендуемый путь.
3. Запушьте и наблюдайте публикацию
С созданным ресурсом, добавленными обоими обязательными секретами и .releaserc.json (плюс шагом установки workflow) на месте, публикация — просто коммит с сообщением в формате conventional-commit и пуш:
git push origin main # or dev, if you kept the dev sandboxТеперь откройте вкладку Actions вашего репозитория. Запуск, названный по имени workflow (Pano Plugin Build), должен появиться в течение минуты. Обычно на завершение уходит несколько минут.
- Зелёная галочка = опубликовано. Откройте ваш ресурс на panomc.com — новая версия должна быть в списке, и владельцы серверов увидят обновление в своей панели под Панель → Дополнения.
- Красный крест = что-то упало. Кликните в упавший шаг, чтобы прочитать ошибку. Две самые частые:
Cannot find module @PanoMC/semantic-release-pano— вы пропустили шаг установки в одном из двух job-ов (шаг 6 / выноска об установке).- Ошибка аутентификации на самом первом шаге — отсутствующий или неправильный секрет
TOKEN_GITHUB(блокTOKEN_GITHUBвыше).
Ручное распространение
Вам не обязательно использовать маркетплейс. Поскольку релизный jar полностью самодостаточен, любой может установить его напрямую:
- Прикрепите jar к релизу GitHub и поделитесь ссылкой, или
- Передайте
.jarвладельцу сервера для загрузки через Панель → Дополнения → Загрузить.
Разница, которую видит пользователь: дополнения, скачанные из маркетплейса, помечены как проверенные, а вручную загруженные jar — нет. Для публичного дополнения маркетплейс настоятельно предпочтителен — он бесплатно даёт вам доставку обновлений, страницу магазина и значок проверенного.
Премиум-листинги
Продажа вашего дополнения работает через тот же поток релиза, плюс встроенный во время сборки ключ лицензии и проверка лицензии во время выполнения, впечённая в ваш код. Полное прохождение — встраивание ключа во время сборки, добавление проверки во время выполнения и связка её в CI — живёт в Премиум-аддоны и лицензирование. Оно строится прямо на этой странице; дополнительные флаги лицензии, которые оно использует (-PlicenseServer, -PpanoLicensePublicKey и переменная окружения PANO_LICENSE_PUBLIC_KEY), также сведены в Конфигурации манифеста.
Куда дальше
- Конфигурация манифеста — поля
gradle.properties, которые CI внедряет во время релиза. - Локализация — отгрузите ваше дополнение на более чем одном языке перед публикацией.