Skip to content

Implement Maven-based plugin management#542

Open
rock3r wants to merge 1 commit intodetekt:mainfrom
rock3r:better-plugin-management
Open

Implement Maven-based plugin management#542
rock3r wants to merge 1 commit intodetekt:mainfrom
rock3r:better-plugin-management

Conversation

@rock3r
Copy link
Contributor

@rock3r rock3r commented Jan 27, 2026

Overview

This PR introduces a sophisticated system for managing detekt plugins directly from the IDE. Users can now extend detekt with third-party rule sets (such as those found on the detekt marketplace) via Maven repositories, complete with automatic transitive dependency resolution and a local lifecycle management system.

Demo:

demo.mp4

Downloaded plugin JARs:
image

Key Advantages

  • No More Manual Hunting: users no longer need to go hunting on GitHub releases or random websites to manually find and download the correct "fat" JARs for plugins. Everything is searchable and resolvable directly within the IDE.
  • Improved Provenance: by resolving artefacts directly from Maven repositories, we eliminate the need to commit binary JARs to the project’s VCS. This simplifies security audits, ensures transparency of library origins, and keeps the repository history lean. It also avoids plonking large fat JAR binary blobs under VCS, which is never ideal.
  • Conflict Prevention: the system automatically identifies and excludes "provided" dependencies (like detekt-api or kotlin-stdlib) from the resolution to ensure plugin JARs don’t cause collisions with the plugin runtime classpath.

Architectural Highlights

  • Plugin Infrastructure: introduced PluginDependencyService to orchestrate the lifecycle of plugin JARs. Plugins are now stored in a project-local folder (.idea/detektPlugins/) and tracked via a state file, downloaded.json.
  • Maven Integration: leveraging IntelliJ’s internal Maven infrastructure (via JarRepositoryManager and ArtifactRepositoryManager), we can reliably discover and resolve detekt plugin artefacts through the new MavenDependencyResolver and MavenArtifactFetcher.
  • Automatic Reconciliation: implemented a synchronisation mechanism that ensures the local plugin folder state matches the current project configuration. This runs as a background task on settings application, project opening, or VCS-triggered state reloads (ensuring team-wide consistency). It cleans up unused JARs and downloads new ones.
  • Dependency Exclusion UI: added an interactive DependencyExclusionEditor for selective exclusion of transitive dependencies. It is a fork of IntelliJ’s own private UI for JPS, but with extra rules and code to support our specific needs.

Further details are available in the DETEKT_PLUGINS.md file, which is provided for guidance and future reference.

Main parts

Component Responsibility
PluginDependencyService Project service handling JAR lifecycle, reconciliation, and clean-up.
MavenSearchDialog New UI for free-text or GAV-based search, version selection, and dependency preview.
DependencyExclusionEditor Tree-based interface for management; forked and adapted from JPS’ internal UI.
DETEKT_PLUGINS.md Comprehensive technical documentation covering data flow and architecture.

Platform Updates

  • Base Version Bump: updated IntelliJ Platform sinceBuild to 242 (2024.2).
  • Toolchain: Updated JVM toolchain to 21 to align with the new base platform requirements.
  • Dependencies: Added org.jetbrains.idea.maven as a required plugin dependency to expose underlying Maven machinery.

Future Improvements

  1. Update Notifications: implement notifications when a newer version of an installed plugin is available on Maven.
  2. Smart Migration: automated migration path for users currently using local plugin JARs to move them to Maven-based management.
  3. Marketplace Integration: pull featured plugins from the marketplace and show them as suggestions in the search field. (Requires the website to host a JSON, or provide an API)
  4. VCS ignore suggestion: if the plugin detects VCS does not ignore the folder, it recommends adding it to the ignored list.

Note

While I have performed extensive manual testing and the PR includes a comprehensive suite of automated tests (covering GAV parsing, cycle detection, and resolution), please perform a thorough manual review and test cycle.

Maven infrastructure can be unpredictable across different environments/caches, and transitive dependency "fun" can manifest in unexpected ways.


Important

AI Disclosure: this change was co-developed using LLM-based agents (primarily Gemini 3 models, and a tiny bit of Claude 4.5 too). That said, all changes in this PR have then been manually reviewed, tweaked, and refactored by yours truly to minimise changes and ensure consistency.

<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Run Plugin" type="GradleRunConfiguration" factoryName="Gradle">
<log_file alias="idea.log" path="$PROJECT_DIR$/build/idea-sandbox/system/log/idea.log" />
<log_file alias="idea.log" path="$PROJECT_DIR$/build/idea-sandbox/IC-*/log/idea.log" />
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had missed this in #539 :)

@rock3r rock3r force-pushed the better-plugin-management branch from eeafa92 to 33d3067 Compare January 27, 2026 10:09
Comment on lines 23 to 34
uses: actions/checkout@v2
uses: actions/checkout@v6

- name: Setup Java
uses: actions/setup-java@v3
uses: actions/setup-java@v5
with:
distribution: 'zulu'
java-version: ${{ matrix.jdk }}
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v5

- name: Build detekt idea plugin
uses: gradle/gradle-build-action@v2
with:
arguments: build --no-daemon
run: ./gradlew build
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The checks failed on Windows for some reason, took the opportunity to updae the actions setup

@rock3r rock3r force-pushed the better-plugin-management branch from 33d3067 to dc4a387 Compare January 27, 2026 10:13
@schalkms schalkms requested a review from arturbosch January 27, 2026 18:54
@cortinico
Copy link
Member

@arturbosch can you review this one?

@arturbosch
Copy link
Member

Yes, I will have some time on the weekend. Sorry for the delay.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a sophisticated Maven-based plugin management system for the Detekt IntelliJ plugin, allowing users to discover, download, and manage third-party rule sets directly from Maven repositories within the IDE. The implementation replaces manual JAR file handling with automatic dependency resolution, transitive dependency management, and a project-local storage system (.idea/detektPlugins/).

Changes:

  • Added Maven-based plugin resolution with automatic dependency management
  • Implemented UI for searching Maven artifacts and customizing transitive dependencies
  • Updated platform requirements to IntelliJ 2024.2 (build 242) and JVM 21
  • Added comprehensive test coverage for dependency resolution, cycle detection, and exclusion logic

Reviewed changes

Copilot reviewed 38 out of 40 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
ProvidedDependenciesTest.kt Tests for identifying dependencies provided by the platform (detekt-api, kotlin-stdlib, etc.)
PluginDependencyServiceTest.kt Tests for plugin lifecycle management including filtering, exclusions, and cycle handling
MavenDependencyResolverTest.kt Tests for Maven coordinate parsing and dependency tree resolution
MavenArtifactFetcherTest.kt Tests for Maven artifact search, version fetching, and GAV parsing
DependencySelectionHandlerTest.kt Tests for checkbox synchronization logic in the dependency tree UI
DependencyCycleTest.kt Tests for handling cyclic dependencies without stack overflow
PluginDependencyService.kt Core service orchestrating plugin download, reconciliation, and cleanup
MavenDependencyResolver.kt Resolves Maven coordinates to full dependency trees with cycle detection
MavenTreeResolver.kt Low-level interface to IntelliJ's Maven infrastructure
MavenSearchDialog.kt UI for searching, selecting versions, and previewing dependencies
DependencyExclusionEditor.kt Tree-based editor for excluding transitive dependencies
DetektPluginSettings.kt Updated to persist Maven plugin configurations and trigger reconciliation
ConfiguredService.kt Modified to include downloaded Maven plugins in classpath
plugin.xml Added Maven module dependency and updated minimum platform version
build.gradle.kts Updated to IntelliJ 2024.2 and JVM 21 with kotlinx exclusions
DETEKT_PLUGINS.md Comprehensive documentation of architecture and data flow
.github/workflows/pre-merge.yaml Updated GitHub Actions versions
Files not reviewed (1)
  • .idea/detekt.xml: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@rock3r rock3r force-pushed the better-plugin-management branch from dc4a387 to 819cfb7 Compare February 8, 2026 02:22
@rock3r
Copy link
Contributor Author

rock3r commented Feb 8, 2026

Build failed due to some silly dependency resolution issue on one of the platforms, please restart it

Copy link
Member

@arturbosch arturbosch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the really cool feature!
This is the first batch of comments. I will continue tomorrow.

btw just found out that we need to opt in for K2 in the plugin:

    <extensions defaultExtensionNs="org.jetbrains.kotlin">
        <supportsKotlinPluginMode supportsK2="true" />
    </extensions>

Seems to work on the first go but not sure if the K1 classes will be deleted in a future release.

For me, resolving detekt-formatting hangs unfortunately:
image

Stacktraces:

2026-02-08 23:12:34,252 [ 623479]   INFO - #c.i.j.s.MavenRepositoryServicesManager - com.intellij.util.io.HttpRequests$HttpStatusException: Request failed with status code 401. Status=401, Url=https://oss.sonatype.org/service/local/search/gavc?g=detekt-&repos=
java.io.IOException: com.intellij.util.io.HttpRequests$HttpStatusException: Request failed with status code 401. Status=401, Url=https://oss.sonatype.org/service/local/search/gavc?g=detekt-&repos=
	at com.intellij.jarRepository.services.artifactory.ArtifactoryRepositoryService.findArtifacts(ArtifactoryRepositoryService.java:82)
	at com.intellij.jarRepository.services.MavenRepositoryServicesManager.findArtifacts(MavenRepositoryServicesManager.java:95)
	at com.intellij.jarRepository.JarRepositoryManager$3.run(JarRepositoryManager.java:467)
	at com.intellij.openapi.progress.impl.CoreProgressManager.startTask(CoreProgressManager.java:534)
	at com.intellij.openapi.progress.impl.ProgressManagerImpl.startTask(ProgressManagerImpl.java:180)
	at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$runProcessWithProgressAsynchronously$7(CoreProgressManager.java:585)
	at com.intellij.openapi.progress.impl.ProgressRunner.lambda$submit$4(ProgressRunner.java:268)
	at com.intellij.openapi.progress.ProgressManager.lambda$runProcess$0(ProgressManager.java:98)
	at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$runProcess$1(CoreProgressManager.java:260)
	at com.intellij.platform.diagnostic.telemetry.helpers.TraceKt.use(trace.kt:44)
	at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$runProcess$2(CoreProgressManager.java:259)
	at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$executeProcessUnderProgress$14(CoreProgressManager.java:717)
	at com.intellij.openapi.progress.impl.CoreProgressManager.registerIndicatorAndRun(CoreProgressManager.java:792)
	at com.intellij.openapi.progress.impl.CoreProgressManager.computeUnderProgress(CoreProgressManager.java:748)
	at com.intellij.openapi.progress.impl.CoreProgressManager.executeProcessUnderProgress(CoreProgressManager.java:716)
	at com.intellij.openapi.progress.impl.ProgressManagerImpl.executeProcessUnderProgress(ProgressManagerImpl.java:75)
	at com.intellij.openapi.progress.impl.CoreProgressManager.runProcess(CoreProgressManager.java:240)
	at com.intellij.openapi.progress.ProgressManager.runProcess(ProgressManager.java:98)
	at com.intellij.openapi.progress.impl.ProgressRunner.lambda$submit$5(ProgressRunner.java:268)
	at com.intellij.openapi.progress.impl.ProgressRunner$ProgressRunnable.run(ProgressRunner.java:546)
	at com.intellij.openapi.progress.impl.ProgressRunner.lambda$launchTask$18(ProgressRunner.java:501)
	at com.intellij.concurrency.ThreadContext.installThreadContext(threadContext.kt:305)
	at com.intellij.openapi.progress.impl.ProgressRunner.lambda$launchTask$19(ProgressRunner.java:500)
	at com.intellij.util.concurrency.ChildContext$runInChildContext$1.invoke(propagation.kt:167)
	at com.intellij.util.concurrency.ChildContext$runInChildContext$1.invoke(propagation.kt:167)
	at com.intellij.util.concurrency.ChildContext.runInChildContext(propagation.kt:173)
	at com.intellij.util.concurrency.ChildContext.runInChildContext(propagation.kt:167)
	at com.intellij.openapi.progress.impl.ProgressRunner.lambda$launchTask$20(ProgressRunner.java:497)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
	at java.base/java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(Executors.java:735)
	at java.base/java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(Executors.java:732)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:400)
	at java.base/java.util.concurrent.Executors$PrivilegedThreadFactory$1.run(Executors.java:732)
	at java.base/java.lang.Thread.run(Thread.java:1583)
Caused by: com.intellij.util.io.HttpRequests$HttpStatusException: Request failed with status code 401. Status=401, Url=https://oss.sonatype.org/service/local/search/gavc?g=detekt-&repos=
	at com.intellij.util.io.HttpRequests.throwHttpStatusError(HttpRequests.java:709)
	at com.intellij.util.io.HttpRequests.openConnection(HttpRequests.java:672)
	at com.intellij.util.io.HttpRequests$RequestImpl.getConnection(HttpRequests.java:381)
	at com.intellij.util.io.HttpRequests$RequestImpl.doReadBytes(HttpRequests.java:457)
	at com.intellij.util.io.HttpRequests$RequestImpl.readString(HttpRequests.java:446)
	at com.intellij.util.io.RequestBuilder.lambda$readString$5(RequestBuilder.java:86)
	at com.intellij.util.io.HttpRequests.doProcess(HttpRequests.java:544)
	at com.intellij.util.io.HttpRequests.process(HttpRequests.java:526)
	at com.intellij.util.io.HttpRequests$RequestBuilderImpl.connect(HttpRequests.java:355)
	at com.intellij.util.io.RequestBuilder.readString(RequestBuilder.java:86)
	at com.intellij.util.io.RequestBuilder.readString(RequestBuilder.java:90)
	at com.intellij.jarRepository.services.artifactory.ArtifactoryRepositoryService.searchArtifacts(ArtifactoryRepositoryService.java:126)
	at com.intellij.jarRepository.services.artifactory.ArtifactoryRepositoryService.findArtifacts(ArtifactoryRepositoryService.java:72)
	... 34 more
2026-02-08 23:12:35,849 [ 625076]   INFO - #c.i.j.s.MavenRepositoryServicesManager - com.intellij.util.io.HttpRequests$HttpStatusException: Request failed with status code 404. Status=404, Url=https://repository.jboss.org/nexus/service/local/data_index?q=detekt-&g=detekt-
java.io.IOException: com.intellij.util.io.HttpRequests$HttpStatusException: Request failed with status code 404. Status=404, Url=https://repository.jboss.org/nexus/service/local/data_index?q=detekt-&g=detekt-
	at com.intellij.jarRepository.services.nexus.NexusRepositoryService.findArtifacts(NexusRepositoryService.java:106)
	at com.intellij.jarRepository.services.MavenRepositoryServicesManager.findArtifacts(MavenRepositoryServicesManager.java:95)
	at com.intellij.jarRepository.JarRepositoryManager$3.run(JarRepositoryManager.java:467)
	at com.intellij.openapi.progress.impl.CoreProgressManager.startTask(CoreProgressManager.java:534)
	at com.intellij.openapi.progress.impl.ProgressManagerImpl.startTask(ProgressManagerImpl.java:180)
	at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$runProcessWithProgressAsynchronously$7(CoreProgressManager.java:585)
	at com.intellij.openapi.progress.impl.ProgressRunner.lambda$submit$4(ProgressRunner.java:268)
	at com.intellij.openapi.progress.ProgressManager.lambda$runProcess$0(ProgressManager.java:98)
	at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$runProcess$1(CoreProgressManager.java:260)
	at com.intellij.platform.diagnostic.telemetry.helpers.TraceKt.use(trace.kt:44)
	at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$runProcess$2(CoreProgressManager.java:259)
	at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$executeProcessUnderProgress$14(CoreProgressManager.java:717)
	at com.intellij.openapi.progress.impl.CoreProgressManager.registerIndicatorAndRun(CoreProgressManager.java:792)
	at com.intellij.openapi.progress.impl.CoreProgressManager.computeUnderProgress(CoreProgressManager.java:748)
	at com.intellij.openapi.progress.impl.CoreProgressManager.executeProcessUnderProgress(CoreProgressManager.java:716)
	at com.intellij.openapi.progress.impl.ProgressManagerImpl.executeProcessUnderProgress(ProgressManagerImpl.java:75)
	at com.intellij.openapi.progress.impl.CoreProgressManager.runProcess(CoreProgressManager.java:240)
	at com.intellij.openapi.progress.ProgressManager.runProcess(ProgressManager.java:98)
	at com.intellij.openapi.progress.impl.ProgressRunner.lambda$submit$5(ProgressRunner.java:268)
	at com.intellij.openapi.progress.impl.ProgressRunner$ProgressRunnable.run(ProgressRunner.java:546)
	at com.intellij.openapi.progress.impl.ProgressRunner.lambda$launchTask$18(ProgressRunner.java:501)
	at com.intellij.concurrency.ThreadContext.installThreadContext(threadContext.kt:305)
	at com.intellij.openapi.progress.impl.ProgressRunner.lambda$launchTask$19(ProgressRunner.java:500)
	at com.intellij.util.concurrency.ChildContext$runInChildContext$1.invoke(propagation.kt:167)
	at com.intellij.util.concurrency.ChildContext$runInChildContext$1.invoke(propagation.kt:167)
	at com.intellij.util.concurrency.ChildContext.runInChildContext(propagation.kt:173)
	at com.intellij.util.concurrency.ChildContext.runInChildContext(propagation.kt:167)
	at com.intellij.openapi.progress.impl.ProgressRunner.lambda$launchTask$20(ProgressRunner.java:497)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
	at java.base/java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(Executors.java:735)
	at java.base/java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(Executors.java:732)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:400)
	at java.base/java.util.concurrent.Executors$PrivilegedThreadFactory$1.run(Executors.java:732)
	at java.base/java.lang.Thread.run(Thread.java:1583)
Caused by: com.intellij.util.io.HttpRequests$HttpStatusException: Request failed with status code 404. Status=404, Url=https://repository.jboss.org/nexus/service/local/data_index?q=detekt-&g=detekt-
	at com.intellij.util.io.HttpRequests.throwHttpStatusError(HttpRequests.java:709)
	at com.intellij.util.io.HttpRequests.openConnection(HttpRequests.java:672)
	at com.intellij.util.io.HttpRequests$RequestImpl.getConnection(HttpRequests.java:381)
	at com.intellij.util.io.HttpRequests$RequestImpl.doReadBytes(HttpRequests.java:457)
	at com.intellij.util.io.HttpRequests$RequestImpl.readString(HttpRequests.java:446)
	at com.intellij.util.io.RequestBuilder.lambda$readString$5(RequestBuilder.java:86)
	at com.intellij.util.io.HttpRequests.doProcess(HttpRequests.java:544)
	at com.intellij.util.io.HttpRequests.process(HttpRequests.java:526)
	at com.intellij.util.io.HttpRequests$RequestBuilderImpl.connect(HttpRequests.java:355)
	at com.intellij.util.io.RequestBuilder.readString(RequestBuilder.java:86)
	at com.intellij.util.io.RequestBuilder.readString(RequestBuilder.java:90)
	at com.intellij.jarRepository.services.nexus.NexusRepositoryService.findArtifacts(NexusRepositoryService.java:89)
	... 34 more
2026-02-08 23:12:36,268 [ 625495]   INFO - #c.i.j.s.MavenRepositoryServicesManager - com.intellij.util.io.HttpRequests$HttpStatusException: Request failed with status code 400. Status=400, Url=https://repository.jboss.org/nexus/service/local/search/gavc?g=detekt-&repos=
java.io.IOException: com.intellij.util.io.HttpRequests$HttpStatusException: Request failed with status code 400. Status=400, Url=https://repository.jboss.org/nexus/service/local/search/gavc?g=detekt-&repos=
	at com.intellij.jarRepository.services.artifactory.ArtifactoryRepositoryService.findArtifacts(ArtifactoryRepositoryService.java:82)
	at com.intellij.jarRepository.services.MavenRepositoryServicesManager.findArtifacts(MavenRepositoryServicesManager.java:95)
	at com.intellij.jarRepository.JarRepositoryManager$3.run(JarRepositoryManager.java:467)
	at com.intellij.openapi.progress.impl.CoreProgressManager.startTask(CoreProgressManager.java:534)
	at com.intellij.openapi.progress.impl.ProgressManagerImpl.startTask(ProgressManagerImpl.java:180)
	at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$runProcessWithProgressAsynchronously$7(CoreProgressManager.java:585)
	at com.intellij.openapi.progress.impl.ProgressRunner.lambda$submit$4(ProgressRunner.java:268)
	at com.intellij.openapi.progress.ProgressManager.lambda$runProcess$0(ProgressManager.java:98)
	at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$runProcess$1(CoreProgressManager.java:260)
	at com.intellij.platform.diagnostic.telemetry.helpers.TraceKt.use(trace.kt:44)
	at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$runProcess$2(CoreProgressManager.java:259)
	at com.intellij.openapi.progress.impl.CoreProgressManager.lambda$executeProcessUnderProgress$14(CoreProgressManager.java:717)
	at com.intellij.openapi.progress.impl.CoreProgressManager.registerIndicatorAndRun(CoreProgressManager.java:792)
	at com.intellij.openapi.progress.impl.CoreProgressManager.computeUnderProgress(CoreProgressManager.java:748)
	at com.intellij.openapi.progress.impl.CoreProgressManager.executeProcessUnderProgress(CoreProgressManager.java:716)
	at com.intellij.openapi.progress.impl.ProgressManagerImpl.executeProcessUnderProgress(ProgressManagerImpl.java:75)
	at com.intellij.openapi.progress.impl.CoreProgressManager.runProcess(CoreProgressManager.java:240)
	at com.intellij.openapi.progress.ProgressManager.runProcess(ProgressManager.java:98)
	at com.intellij.openapi.progress.impl.ProgressRunner.lambda$submit$5(ProgressRunner.java:268)
	at com.intellij.openapi.progress.impl.ProgressRunner$ProgressRunnable.run(ProgressRunner.java:546)
	at com.intellij.openapi.progress.impl.ProgressRunner.lambda$launchTask$18(ProgressRunner.java:501)
	at com.intellij.concurrency.ThreadContext.installThreadContext(threadContext.kt:305)
	at com.intellij.openapi.progress.impl.ProgressRunner.lambda$launchTask$19(ProgressRunner.java:500)
	at com.intellij.util.concurrency.ChildContext$runInChildContext$1.invoke(propagation.kt:167)
	at com.intellij.util.concurrency.ChildContext$runInChildContext$1.invoke(propagation.kt:167)
	at com.intellij.util.concurrency.ChildContext.runInChildContext(propagation.kt:173)
	at com.intellij.util.concurrency.ChildContext.runInChildContext(propagation.kt:167)
	at com.intellij.openapi.progress.impl.ProgressRunner.lambda$launchTask$20(ProgressRunner.java:497)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
	at java.base/java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(Executors.java:735)
	at java.base/java.util.concurrent.Executors$PrivilegedThreadFactory$1$1.run(Executors.java:732)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:400)
	at java.base/java.util.concurrent.Executors$PrivilegedThreadFactory$1.run(Executors.java:732)
	at java.base/java.lang.Thread.run(Thread.java:1583)
Caused by: com.intellij.util.io.HttpRequests$HttpStatusException: Request failed with status code 400. Status=400, Url=https://repository.jboss.org/nexus/service/local/search/gavc?g=detekt-&repos=
	at com.intellij.util.io.HttpRequests.throwHttpStatusError(HttpRequests.java:709)
	at com.intellij.util.io.HttpRequests.openConnection(HttpRequests.java:672)
	at com.intellij.util.io.HttpRequests$RequestImpl.getConnection(HttpRequests.java:381)
	at com.intellij.util.io.HttpRequests$RequestImpl.doReadBytes(HttpRequests.java:457)
	at com.intellij.util.io.HttpRequests$RequestImpl.readString(HttpRequests.java:446)
	at com.intellij.util.io.RequestBuilder.lambda$readString$5(RequestBuilder.java:86)
	at com.intellij.util.io.HttpRequests.doProcess(HttpRequests.java:544)
	at com.intellij.util.io.HttpRequests.process(HttpRequests.java:526)
	at com.intellij.util.io.HttpRequests$RequestBuilderImpl.connect(HttpRequests.java:355)
	at com.intellij.util.io.RequestBuilder.readString(RequestBuilder.java:86)
	at com.intellij.util.io.RequestBuilder.readString(RequestBuilder.java:90)
	at com.intellij.jarRepository.services.artifactory.ArtifactoryRepositoryService.searchArtifacts(ArtifactoryRepositoryService.java:126)
	at com.intellij.jarRepository.services.artifactory.ArtifactoryRepositoryService.findArtifacts(ArtifactoryRepositoryService.java:72)
	... 34 more

@rock3r
Copy link
Contributor Author

rock3r commented Feb 12, 2026

I think the issue you were seeing was backend related — the 404s are expected when the search returns nothing, the 401 is weird and probably some transient issue. I am adding a bunch of extra logic and tests to improve error handling, anyway.

This commit introduces a system for managing detekt plugins directly
from the IDE, allowing users to add third-party rule sets from Maven
repositories with automatic transitive dependency resolution.

Architectural highlights:
- Plugin Infrastructure: introduced `PluginDependencyService` to
  orchestrate the lifecycle of plugin JARs. Plugins are now stored in a
  project-local folder (`.idea/detektPlugins/`) and tracked via a state
  file, `downloaded.json`.
- Maven Integration: using IntelliJ's internal Maven infrastructure (via
  `JarRepositoryManager` and `ArtifactRepositoryManager`), we can now
  reliably discover and resolve detekt plugin artefacts, through the
  new `MavenDependencyResolver` and `MavenArtifactFetcher`.
- Automatic Reconciliation: implemented a synchronization mechanism that
  ensures the local plugin folder matches the current project
  configuration. This runs as a background task on settings apply,
  project open, or VCS-triggered state reloads.
- Dependency Exclusion UI: added an interactive
  `DependencyExclusionEditor` that allows users to selectively exclude
  transitive dependencies if they so wish. It includes smart propagation
  rules via `DependencySelectionHandler` and the "provided" dependency
  protection to prevent classpath conflicts with the IDE runtime.
- Analysis Integration: `ConfiguredService` now dynamically discovers
  and includes downloaded JARs in the detekt analysis classpath,
  ensuring that third-party rules are applied immediately after they are
  downloaded.

Main components:
- `PluginDependencyService`: Project service for JAR lifecycle,
  reconciliation, and cleanup.
- `MavenSearchDialog`: new UI for free text or GAV-based search, version
  selection, and transitive dependency exclusion.
- `DependencyExclusionEditor`: checkbox-tree interface for transitive
  dependency management. Forked from JPS' own (private) equivalent UI.
- `DETEKT_PLUGINS.md`: New technical documentation covering the
  architecture and data flow. AI-generated/human-refined summary of the
  structure and architecture of the feature, to ease future maintenance.

Platform updates:
- Bumped IntelliJ Platform sinceBuild to 242 and updated JVM toolchain
  to 21 to match the new base IJPL version's.
- Added `org.jetbrains.idea.maven` as a required plugin dependency, as
  it exposes the Maven machinery we use under the hood.
- Refined dependency exclusions in `build.gradle.kts` to avoid runtime
  leaks and conflicts.

Areas Touched:
- Configuration: `DetektConfig`, `DetektPluginSettings`, `.idea/detekt
.xml`.
- Runtime: `ConfiguredService` (classpath management), `plugin.xml`.
- UI: Main settings panel (`DetektConfigUi`) and a new `ui` package for
Maven interaction.
- Tests: Comprehensive suite covering GAV parsing, cycle detection, and
resolution logic.

AI Disclosure:
This change was co-developed using LLM-based agents (primarily Gemini 3
models, and a bit of Claude 4.5 too). That said, all the code has been
at least manually reviewed, and often tweaked or refactored too, by hand
by the author.
@rock3r rock3r force-pushed the better-plugin-management branch from 819cfb7 to 99fed7f Compare February 12, 2026 18:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants