Marketplace
Анализ интеграции IDEA c кастомным Marketplace
Цель - реализация собственного маркетплейса для Intellij IDEA взамен использования https://plugins.jetbrains.com/ (далее - JB Marketplace).
В ходе анализа сравниваются два подхода:
- Встроенный механизм Custom plugin repositories
- Реализация подмножества API, используемого IDEA Marketplace plugin. Описание API: https://plugins.jetbrains.com/docs/marketplace/api-reference.html
Ответы на поставленные вопросы
-
Убедиться в плохом решение через uploadPlugin.xml
Реализация с помощью Marketplace API более целесообразна, т.к. предоставляет большую гибкость и позволяет заместить обращения к JB Marketplace. -
Понять можем ли мы поставлять плагины из кастомного маркетплейса через JB marketplace api
Можем, при условии реализации endpoint-ов, используемых IDEA. -
Примерно оценить трудозатраты со стороны IDEA (client)
Перенаправить IDEA на кастомный маркетплейс можно с помощью параметра конфигурации.
Изменения со стороны IDEA могут потребоваться, если нужно изменить поведение и настройки по умолчанию, а также убрать логику, специфичную для ultimate и других JB аддонов. -
Можем ли мы использовать одновременно плагины из JB marketplace и нашего кастомного?
Объединение данных об аддонах из кастомного маркетплейса и из JB Marketplace можно реализовать на уровне сервера.
Использование Custom plugin repositories
Для использования механизма Custom plugin repositories достаточно реализовать endpoint, возвращающий данные плагинов в поддерживаемом формате.
В запросе к репозиторию передаётся параметр build - версия IDEA.
Ограничения:
- IDEA отображает Custom plugin repositories в отдельных группах в Settings | Plugins | Marketplace
- IDEA продолжит обращаться к хосту маркетплейса (JB Marketplace по умолчанию)
- Касательно release channel - каналы не используются в IDEA. API endpoint
/channels/listпомечен как deprecated. Штатный способ установки плагина из канала на https://plugins.jetbrains.com/ - установка URL конкретного канала в качестве Custom plugin repository. Например, single plugin - https://plugins.jetbrains.com/plugins/nightly/10081, all plugins - https://plugins.jetbrains.com/plugins/nightly/list.
Полезные property
intellij.plugins.custom.built.in.repository.url
Позволяет указать встроенный кастомный репозиторий плагинов.
Формат данных
Custom plugin repositories поддерживает два формата данных:
- updates.xml
- plugins.jetbrains.com
updates.xml
Note: В примере приведён не полный список возможных полей.
<?xml version="1.0" encoding="UTF-8"?>
<plugins>
<plugin
id="fully.qualified.id.of.this.plugin"
url="https://mycompany.example.com/my_repo/my_plugin.jar"
version="major.minor.update">
<idea-version since-build="181.3" until-build="191.*"/>
</plugin>
<plugin
id="id.of.different.plugin"
url="https://othercompany.example.com/other_repo/other_plugin.jar"
version="major.minor">
<idea-version since-build="181.3" until-build="191.*"/>
</plugin>
</plugins>
plugins.jetbrains.com
<?xml version='1.0' encoding='UTF-8'?>
<plugin-repository>
<ff>"Editor"</ff>
<category name="Editor">
<idea-plugin downloads="238085" size="67900" date="1719996938000" updatedDate="1719996938000" url="">
<name>IdeaVim-EasyMotion</name>
<id>org.jetbrains.IdeaVim-EasyMotion</id>
<description>
<![CDATA[EasyMotion plugin emulation for IdeaVim]]>
</description>
<version>1.15</version>
<vendor email="support@jetbrains.com" url="https://www.jetbrains.com/">JetBrains</vendor>
<rating>4.2</rating>
<change-notes>
<![CDATA[Fix https://github.com/AlexPl292/IdeaVim-EasyMotion/issues/56]]>
</change-notes>
<idea-version min="n/a" max="n/a" since-build="241.15989.150"/>
<depends>AceJump</depends>
<depends>IdeaVIM</depends>
<depends>com.intellij.modules.platform</depends>
<tags>Editor</tags>
</idea-plugin>
<idea-plugin downloads="16479367" size="5616586" date="1724073309000" updatedDate="1724073309000" url="https://plugins.jetbrains.com/plugin/164">
<name>IdeaVim</name>
<id>IdeaVIM</id>
<description>
<![CDATA[<p>Vim engine for JetBrains IDEs</p>]]>
</description>
<version>2.16.0</version>
<vendor email="support@jetbrains.com" url="https://www.jetbrains.com/">JetBrains</vendor>
<rating>4.5</rating>
<change-notes>
<![CDATA[Undo in IdeaVim now works like in Vim]]>
</change-notes>
<idea-version min="n/a" max="n/a" since-build="241.15989"/>
<depends>com.intellij.modules.platform</depends>
<tags>Editor</tags>
<tags>Keymap</tags>
</idea-plugin>
</category>
</plugin-repository>
Properties
| Name | update.xml | plugins.jetbrains.com |
|---|---|---|
| Category | N/A | /plugin-repository/category/@name |
| Id | /plugins/plugin/@id | /plugin-repository/category/idea-plugin/id |
| Downloads | N/A | /plugin-repository/category/idea-plugin/@downloads |
| Size | N/A | /plugin-repository/category/idea-plugin/@size |
| Url | N/A | /plugin-repository/category/idea-plugin/@url |
| IDEA Version - since build | /plugins/plugin/idea-version/@since-build | /plugin-repository/category/idea-plugin/idea-version/@since-build |
| IDEA Version - until build | /plugins/plugin/idea-version/@since-build | /plugin-repository/category/idea-plugin/idea-version/@until-build |
| Download URL | /plugins/plugin/@url | /plugin-repository/category/idea-plugin/download-url |
| Version | /plugins/plugin/@version | /plugin-repository/category/idea-plugin/version |
| Date | N/A | /plugin-repository/category/idea-plugin/@date |
| Updated date | N/A | /plugin-repository/category/idea-plugin/@updatedDate |
| Vendor Email | N/A (?) | /plugin-repository/category/idea-plugin/vendor/@email |
| Vendor URL | N/A (?) | /plugin-repository/category/idea-plugin/vendor/@url |
| Change notes | /plugins/plugin/change-notes | /plugin-repository/category/idea-plugin/change-notes |
| Description | /plugins/plugin/description | /plugin-repository/category/idea-plugin/description |
| Name | /plugins/plugin/name | /plugin-repository/category/idea-plugin/name |
| Depends | N/A (?) | /plugin-repository/category/idea-plugin/depends |
| Tags | N/A (?) | /plugin-repository/category/idea-plugin/tags |
| Product code | N/A (?) | /plugin-repository/category/idea-plugin/productCode |
| Rating | N/A (?) | /plugin-repository/category/idea-plugin/rating |
IDEA Marketplace API
Для интеграции через API маркетплейса IDEA требуется реализовать endpoint-ы, используемые в Marketplace plugin.
Base URLs
-
URL of plugins repository instance
Default value:https://plugins.jetbrains.comfun getPluginManagerUrl() = MarketplaceCustomizationService.getInstance().getPluginManagerUrl().trimEnd('/')- Можно переопределить в собственной реализации
MarketplaceCustomizationService - Настраивается с помощью property:
idea.plugins.host
- Можно переопределить в собственной реализации
-
Plugin download base URL
Default value:${pluginManagerUrl}/pluginManager/private fun getDownloadUrl() = MarketplaceCustomizationService.getInstance().getPluginDownloadUrl().trimEnd('/')- Можно переопределить в собственной реализации
MarketplaceCustomizationService
- Можно переопределить в собственной реализации
Endpoint URLs
-
Plugin download URL
Value:${pluginDownloadUrl}?id=${pluginId}&build=${IDE_BUILD_FOR_REQUEST}&uuid=${marketplaceDownloadsUUID}&updatedFrom=${currentVersion}&channel=${channel}
Params:buildmarketplaceDownloadsUUID- уникальный идентификатор машины, генерируется с помощью DeviceIdManagercurrentVersionchannel
private fun getDownloadUrl() = MarketplaceCustomizationService.getInstance().getPluginDownloadUrl().trimEnd('/') ** * Download the latest compatible update for plugin [ProductFamily.INTELLIJ] by IDE Version. * @param xmlId plugin XML id. * @param ideBuild IDE version. Example: "IC-145.184" * @param channel plugin channel. Default value is "stable" plugin channel. */- Из plugin-repository-rest-client также передаётся параметр
action=download
-
Plugin metadata URL
Value:${pluginManagerUrl}/files/${externalPluginId}/meta.json
Params:externalPluginId
-
Plugin update metadata URL
Value:${pluginManagerUrl}/files/${externalPluginId}/${externalUpdateId}/meta.json/** * Get plugin update metadata. * * Supported for [ProductFamily.INTELLIJ] only. */ -
All available JetBrains plugins IDs URL
Value:${pluginManagerUrl}/files/jbPluginsXMLIds.json -
All Intellij plugins IDs URL
Value:${pluginManagerUrl}/files/pluginsXMLIds.json/** * Get All [ProductFamily.INTELLIJ] plugins IDs. */ -
Broken plugins JSON URL
Value:${pluginManagerUrl}/files/brokenPlugins.json -
Supported IDE extensions JSON URL
Value:${pluginManagerUrl}/files/IDE/extensions.json?build=${IDE_BUILD_FOR_REQUEST}
Params:build
-
Marketplace features URL
Value:${pluginManagerUrl}/feature/getImplementations?featureType=${featureType}&implementationName=${implementationName}&build=${IDE_BUILD_FOR_REQUEST}
Params:featureTypeimplementationNamebuild
-
Search aggregation URL
Value:${pluginManagerUrl}/api/search/aggregation/${field}?build=${IDE_BUILD_FOR_REQUEST}
Params:field- принимаемые значения:tags,organizationsbuild
-
Search last compatible update URL
Value:${pluginManagerUrl}/api/search/compatibleUpdates/** * Search last compatible update for each ID` from [xmlIds] or by declared [module] * Supported for [ProductFamily.INTELLIJ]. * @return the list of last compatible updates [UpdateBean] for plugins from [xmlIds]. */ -
Search nearest update URL
Value:${pluginManagerUrl}/api/search/updates/nearest -
Search plugins URL
Value:${pluginManagerUrl}/api/search/plugins?${query}&build=${IDE_BUILD_FOR_REQUEST}&max=${count}&all=${includeIncompatible}
Params:querybuildmaxall
-
Plugin reviews URL
Value:${pluginManagerUrl}/api/products/intellij/plugins/${pluginId}/comments${page}
Params:pluginIdpage
-
Plugin homepage URL
Default value:${pluginManagerUrl}/plugin/index?xmlId=${pluginId}
Params:pluginId
fun getPluginHomepage(pluginId: PluginId): String? = MarketplaceCustomizationService.getInstance().getPluginHomepageUrl(pluginId)- Можно переопределить в собственной реализации
MarketplaceCustomizationService
-
Plugin reviews policy URL
Value:${pluginManagerUrl}/docs/marketplace/reviews-policy.html -
Plugin write review URL
Value:${pluginManagerUrl}/intellij/${pluginId}/review/new?build=${IDE_BUILD_FOR_REQUEST}&version=${version}
Deprecated
-
Channels list URL
Default value:${getPluginManagerUrl()}/channels/list//** * @deprecated is not used by the platform anymore */ -
Plugins list URL
Default value:${getPluginManagerUrl()}/plugins/list/?uuid=${marketplaceDownloadsUUID}
Params:marketplaceDownloadsUUID- уникальный идентификатор машины, генерируется с помощью DeviceIdManager
/** * List of plugins compatible with [ideBuild] * @deprecated use [searchCompatibleUpdates] for getting compatible update IDs and [PluginUpdateManager.getIntellijUpdateMetadata] for getting information */ @Deprecated("Will be removed for performance reasons")- Можно переопределить в собственной реализации
MarketplaceCustomizationService
Другие полезные источники
- Extension backup file
Value:${PathManager.getTempPath()}/pluginsFeatures.json
Приоритет реализации endpoint-ов
| Name | URL | Priority |
|---|---|---|
| Plugin download | /pluginManager/ | A |
| Plugin metadata | /files/$/meta.json | A |
| Plugin update metadata | /files/$/$/meta.json | A |
| All available JetBrains plugins IDs | /files/jbPluginsXMLIds.json | B |
| All Intellij plugins IDs | /files/pluginsXMLIds.json | A |
| Broken plugins JSON | /files/brokenPlugins.json | B |
| Supported IDE extensions JSON | /files/IDE/extensions.json | B |
| Marketplace features | /feature/getImplementations | B |
| Search aggregation | /api/search/aggregation/$ | A |
| Search last compatible update | /api/search/compatibleUpdates | A |
| Search nearest update | /api/search/updates/nearest | A |
| Search plugins | /api/search/plugins | A |
| Plugin reviews | /api/products/intellij/plugins/$/comments$ | C |
| Plugin homepage | /plugin/index | B |
| Plugin reviews policy | /docs/marketplace/reviews-policy.html | C |
| Plugin write review | /intellij/$/review/new | C |