November 19, 2025
For Victoria Alajemba, a Software Engineer from Nigeria studying in Paris, GSoC was a bridge between learning and impact. Working on the IntelliJ Platform Gradle Plugin, she integrated Gradle’s Problems API and Reporting API, creating richer, standardized reports and exploring parallel verification for faster builds. Guided by Jakub Chrzanowski from JetBrains, she strengthened key workflows used by thousands of plugin developers.
Mentor: Jakub Chrzanowski (JetBrains)
I am Victoria Chuks Alajemba, a software engineer passionate about developer tooling from Nigeria. I’ve been building mobile applications professionally since 2021, after learning programming via YouTube in 2020, and I am currently exploring the world of plugins and extensions across several platforms like the IntelliJ Platform, VS Code, Chrome, and more. I love developer tools and programming in general, but more than that, I love the idea of being able to create something that solves a problem. I currently study artificial intelligence and data science for businesses at aivancity School of AI & Data for Business & Technology in Paris.
The IntelliJ Platform Gradle Plugin is a critical tool for developers building plugins that target the IntelliJ Platform. It is used by JetBrains and third-party developers to build, test, verify, and publish their plugins. Improvements to this tool will ensure that the thousands of developers who rely on it have a great experience.
The verifyPlugin task, a Gradle task that is part of the IntelliJ Platform Gradle Plugin, enables developers to check that their plugin works against various IntelliJ-based IDEs (PyCharm, Android Studio, IntelliJ IDEA Community Edition, and more). However, the IntelliJ Platform Gradle Plugin team had identified certain areas for enhancement:
ProblemIds organized by:
ProblemGroups Groups.VerifyPlugin for verification-specific issues.VerificationFailure factory generating ProblemIds from FailureLevel enum./**
* Contains problem IDs to be used when reporting a problem with the Problems API
* for the IntelliJ Platform Gradle Plugin.
*
* @see org.gradle.api.problems.ProblemId
* @see org.gradle.api.problems.Problems
*/
@Suppress("UnstableApiUsage")
internal object Problems {
/**
* Contains [ProblemGroup]s to be used with the Problems API for the IntelliJ Platform Gradle Plugin.
*/
private object Groups {
val IntelliJPlatformPlugin = ProblemGroup.create(
"intellij-platform-plugin-group",
"IntelliJ Platform Plugin Problems"
)
val VerifyPlugin = ProblemGroup.create("$ID.verify-plugin", "Verify Plugin")
}
object VerifyPlugin {
val InvalidPlugin = ProblemId.create(
"invalid-plugin",
"Invalid Plugin",
Groups.VerifyPlugin,
)
// ....
}
}
reportError() helper: Wraps exceptions with Problems API metadata, including clickable report URLs./**
* Helper function to report an error using the Problems API.
*
* @param exception The exception to report. It is suppressed to allow a wrapper exception be thrown with an updated message.
* @param problemId The ID of the problem to report.
* @param problemsReportUrl Optional URL used to include the report file's path to the exception's message.
* Expected value: [org.gradle.api.file.ProjectLayout.getBuildDirectory]/reports/problems/problems-report.html
* @param spec An action that further configures the problem specification.
* @return A RuntimeException that includes the original exception and the problem details.
*/
internal fun ProblemReporter.reportError(
exception: Exception,
problemId: ProblemId,
problemsReportUrl: String?,
spec: Action<ProblemSpec>
): RuntimeException {
val message = buildString {
append(exception.message)
if (problemsReportUrl != null) {
append("${System.lineSeparator()}[Incubating] See full report here: $problemsReportUrl")
}
}
return throwing(RuntimeException(message).also { it.addSuppressed(exception) }, problemId) {
spec.execute(this)
withException(exception)
severity(Severity.ERROR)
}
}
collectProblems() → parseItemsToMap() → structured ProblemSpec generation.FailureLevel enum values map to Severity.ERROR/WARNING based on configuration.Sample in BuildScan:
In-IDE sample:
VerifyPluginConfigurationReportsImpl: DelegatingReportContainer delegating to DefaultReportContainer.open class VerifyPluginConfigurationReportsImpl @Inject constructor(
owner: Describable,
objectFactory: ObjectFactory,
) : DelegatingReportContainer<SingleFileReport>(
DefaultReportContainer.create(
objectFactory,
SingleFileReport::class.java
) { factory ->
val list: Collection<SingleFileReport> = ImmutableList.of(
factory.instantiateReport(DefaultSingleFileReport::class.java, "txt", owner)
)
list
}
), VerifyPluginConfigurationReports {
override val txt: SingleFileReport
get() = getByName("txt")
}
SingleFileReport generation → configurable output.// Task DSL configuration
reports {
txt.required.set(true)
txt.outputLocation.convention(
project.layout.buildDirectory.file("reports/verifyPluginConfiguration/report.txt")
)
}
@Inject ObjectFactory for report instance creation.@CacheableTask
abstract class VerifyPluginProjectConfigurationTask : DefaultTask(), IntelliJPlatformVersionAware, KotlinMetadataAware,
RuntimeAware, PluginAware, ModuleAware, Reporting<VerifyPluginConfigurationReports> {
/**
* Service for creating custom Gradle types
*/
@get:Inject
abstract val objectFactory: ObjectFactory
…
/**
* Container for results generated from verifying the plugin's project configuration.
*
* Output location is configured using [org.gradle.api.reporting.internal.DefaultSingleFileReport.getOutputLocation].
* Default value: [org.gradle.api.file.ProjectLayout.getBuildDirectory]/reports/verifyPluginConfiguration/report.txt
*/
private val reports: VerifyPluginConfigurationReports = objectFactory.newInstance(
VerifyPluginConfigurationReportsImpl::class.java,
Describables.quoted("Task", identityPath)
)
private val txtReportFile get() = if (reports.txt.required.get()) reports.txt.outputLocation else null
...
}
I've been using Kotlin since I started programming about four years ago through Android development. Contributing to Kotlin has been on my mind for a while, but the main Kotlin repository seemed daunting to dive into. When I discovered Google Summer of Code, it felt like the perfect structured opportunity to finally contribute meaningfully to the Kotlin ecosystem.
The IntelliJ Platform Gradle Plugin project immediately caught my attention because I'd already been building IntelliJ Platform plugins myself. I had even documented my migration experience to the new IntelliJ Platform Gradle Plugin, which gave me some familiarity with the tool's API. At my core, I see myself as more of a user than just a developer, so I'm passionate about improving the tools I actually use daily.
Creating my proposal was an intensive research process that took several weeks, and here's how I approached it:
While putting together my proposal, I made sure to ask questions about it on the org’s Slack channel. Doing this demonstrated my dedication and the kind of insight I already had for the project.
I dived into the IntelliJ Platform Gradle Plugin source code, focusing on the key parts outlined in the project description:
@TaskAction
override fun exec() {
with(ides) {
...
args(listOf("check-plugin")...)
...
ByteArrayOutputStream().use { os ->
super.exec()
}
...
}
}
ExecutorService in com.jetbrains.pluginverifier.runSeveralVerifiers.I researched similar implementations in the Gradle ecosystem:
I also built prototypes:
Reporting API prototype: I created a working implementation on VerifyPluginProjectConfigurationTask (a simpler task that handles its own reporting). This proved that Gradle Reporting API integration was feasible and showed I understood the technical challenges.
Worker API prototype: I implemented a basic Worker API integration for VerifyPluginTask using process isolation mode:
abstract class VerifyPluginTask : DefaultTask() {
@get:Inject
abstract val workerExecutor: WorkerExecutor
@TaskAction
fun verifyAction() {
val workQueue = workerExecutor.processIsolation()
workQueue.submit(VerificationTaskWork::class.java) {
// Set parameters for isolated execution
}
}
}
Full implementation available here.
I identified potential blockers:
VerifyPluginTask delegates reporting to the Verifier CLI, we might need to update the CLI to output List\<PluginVerificationResult\> differently.Being upfront about these risks showed I understood the complexity, not just the ideal outcomes.
I broke down my timeline into specific, measurable tasks:
I was honest about my situation and experience:
I also highlighted relevant experience:
Looking back, the time I invested in understanding the architecture and building prototypes was crucial. It gave me confidence in what I proposed and helped me hit the ground running when the program started.
My contributions:
I'd love to connect with fellow developers working on build tools, Gradle plugins, IntelliJ Platform development, or Kotlin, or explore any roles related to this!