| name | module-set-pluginization |
| description | Convert Product DSL module sets into generated plugin wrappers and handle the surrounding generation flow. Use when pluginizing a module set like `recentFiles` or `grid.core`, updating bundled plugin registration, regenerating wrapper artifacts, fixing validation/build ordering bugs where wrapper plugin descriptors are needed before generated files exist on disk, or fixing tests whose plugin loading logs show missing generated module-set wrapper plugins. |
Module Set Pluginization
Use this workflow when a Product DSL ModuleSet should become a generated plugin wrapper.
Before Editing
- Read
community/platform/build-scripts/product-dsl/.claude/rules/product-dsl.md before changing product-dsl sources.
- Find an existing pluginized example first, usually
recentFiles() or vcsFrontend(), and mirror its packaging pattern before inventing a new one.
- Confirm whether the target should stay inlined inside a parent module set. Pluginized wrappers usually stop being emitted through the old generated
intellij.moduleSets.<name>.xml path.
Convert the DSL Definition
- Change the module-set function from
moduleSet("name") to plugin("name").
- Keep the content modules unchanged unless the product layout itself is also changing.
- Remove stale
moduleSet(...) inclusions from aggregate module sets if the wrapper should no longer be inlined there.
- If the wrapper should be bundled by default, add
intellij.moduleSet.plugin.<name> to DEFAULT_BUNDLED_PLUGINS in ProductModulesLayout.kt.
- Check products that override or reset default bundled plugins. JetBrains Client often needs explicit wiring in both product-module XML and Kotlin product layout code.
Fix Ordering Bugs When Validation Runs Before Generation
If pluginization causes failures like "plugin missing" or unresolved dependencies before generated wrapper files exist on disk, preload wrapper plugin content in memory.
- Add a cache path for precomputed plugin content in
PluginContentCache.
- Build
PluginContentInfo objects for pluginized module sets from the same data used by ModuleSetPluginGenerator.
- Inject those precomputed wrapper descriptors in
ModelBuildingStage before plugin extraction and validation start.
- Prefer this over reordering the entire pipeline. The goal is to make validation independent from already-generated wrapper files being present on disk.
Expected Generated Churn
- New wrapper directory under
community/module-set-plugins/generated/intellij.moduleSet.plugin.<name>/ with:
<module>.iml
plugin-content.yaml
resources/META-INF/plugin.xml
BUILD.bazel after JPS-to-Bazel sync
- Update of
community/module-set-plugins/generated/intellij.moduleSet.plugin.main/
- Deletion of the legacy generated
community/platform/platform-resources/generated/META-INF/intellij.moduleSets.<name>.xml
- Updates to any generated aggregators or xi:include-based product descriptors that previously referenced the legacy module-set XML
.idea/modules.xml and community/.idea/modules.xml updates after generator + JPS-to-Bazel sync
- Product content snapshots for products affected by default bundled plugin changes. Keep unrelated dirty snapshot or plugin-dependency diffs out of the migration unless the packaging test proves they are caused by the new wrapper.
Required Commands
Run these in order after the source edits:
bazel run //platform/buildScripts:plugin-model-tool
./build/jpsModelToBazel.cmd
./build/jpsModelToBazel.cmd is required because generated wrapper .iml files and BUILD.bazel files change together.
Downstream Test Runtime Dependencies
Pluginization can break narrow test modules even when product packaging tests pass. Test runtime classpaths may still include a plugin module whose extracted platform dependency is no longer embedded. Catch this from idea.log, not from test assertion text alone.
- Inspect
Plugin set resolution and Problems found loading plugins in local or TeamCity test logs.
- Treat messages such as missing
intellij.platform.structureView.impl, intellij.platform.execution.serviceView, or intellij.platform.todo as likely missing intellij.moduleSet.plugin.structureView, intellij.moduleSet.plugin.servicesView, or intellij.moduleSet.plugin.todoView runtime dependencies.
- Add generated wrapper deps only to the affected test module with
scope="RUNTIME". Do not add them to broad shared modules such as intellij.platform.testFramework or aggregate/global test infrastructure.
- After changing
.iml, run ./build/jpsModelToBazel.cmd and verify the generated BUILD.bazel runtime deps are updated.
- For TeamCity, read the published test log artifact when needed:
/app/rest/builds/id:<buildId>/artifacts/content/testlog.zip!.../idea.log.
Pre-TeamCity Canary Suite
Run this suite before relying on TeamCity after module-set wrapper or plugin dependency changes. The order is intentional: fix failures in checks 1-5 before interpreting downstream canary failures.
- Embedded dependency closure:
./bazel.cmd run //platform/buildScripts:plugin-model-tool -- --json='{"filter":"embeddedDependencyClosure","pluginSourceOnly":true}'
- Product DSL module-set validation:
./tests.cmd --module intellij.platform.buildScripts.productDsl.tests --test org.jetbrains.intellij.build.productLayout.validator.ProductModuleSetValidatorTest
- Fast project structure/root packages:
./tests.cmd --module intellij.projectStructureTests --test com.intellij.ideaProjectStructure.fast.IntelliJProjectPackageNamesTest
- Ultimate plugin module dependencies:
./tests.cmd --module intellij.idea.ultimate.build.tests --test com.intellij.idea.ultimate.build.smokeTests.IdeaUltimatePluginModuleDependenciesTest
- Product packaging baseline:
./tests.cmd --module intellij.idea.ultimate.build.tests --test com.intellij.idea.ultimate.build.smokeTests.AllProductsPackagingTest
- Database and SQL wrapper coverage:
./tests.cmd --module intellij.database.sql.tests --test com.intellij.sql.SqlFileStructureViewTest
./tests.cmd --module intellij.database.sql.tests --test com.intellij.sql.editor.SqlMultiLineTodoTest
./tests.cmd --module intellij.database.tests --test com.intellij.database.view.DatabaseViewTest
- Shell plus Markdown plugin loading:
./community/tests.cmd --module intellij.sh.tests --test com.intellij.sh.highlighting.ShHighlightUsagesInMarkdownTest
- Ruby plus SQL injection plugin loading:
./tests.cmd --module intellij.ruby.tests --test org.jetbrains.plugins.ruby.ruby.psi.RubyHeredocInjectorTest#testSqlHeredoc
- RustRover structure and SQL loading:
./tests.cmd --module intellij.rustrover.core.test --test org.rust.ide.structure.RsStructureViewModelTest
./tests.cmd --module intellij.rustrover.sql.tests --test com.jetbrains.rust.sql.SqlInjectorTest
- ReSharper external services/DataGrip bridge:
./tests.cmd --module intellij.resharper.external.services.test.cases.rd --test com.jetbrains.resharper.external.services.test.cases.ReSharperDataGripRdTest
Verification
- Run
lint_files() on every changed Kotlin source and test file.
- Run the Pre-TeamCity Canary Suite after generated files and narrow test dependencies are updated.
- After platform packaging checks are clean, run CLion and Rider packaging tests when product-specific packaging may be affected:
./tests.cmd --module intellij.clion.build.tests --test org.jetbrains.intellij.build.clion.CLionPackagingTest
./tests.cmd --module intellij.rider.build.tests --test com.jetbrains.rider.build.RiderPackagingTest
- Run at least one representative test from each affected test module via
./tests.cmd --module <module> --test <FQN or FQN#method>. Prefer a small smoke test that exercises plugin loading without external fixtures.
- If the original CI test needs unavailable data or services, run a nearby smoke test and document the local blocker. Confirm
idea.log no longer reports the original missing generated wrapper plugin.
- Add or update a regression test that proves the wrapper exists in memory before generated files are written if you touched pipeline ordering.
- Use targeted tests with fully qualified names:
./tests.cmd -Dintellij.build.test.patterns=org.jetbrains.intellij.build.productLayout.generator.ModuleSetPluginGeneratorTest
./tests.cmd -Dintellij.build.test.patterns=org.jetbrains.intellij.build.productLayout.pipeline.ModelBuildingStageTest
./tests.cmd -Dintellij.build.test.patterns=org.jetbrains.intellij.build.productLayout.validator.ModuleSetPluginizationValidatorTest
./tests.cmd -Dintellij.build.test.patterns=org.jetbrains.intellij.build.productLayout.dependency.PluginDependencyGraphTest
Add product-specific packaging tests only if the generated diff or failing tests show downstream expectations need updates.