How do I remove product-descriptor tag from plugin.xml when running the IDE?

I can’t figure this out and I don’t get why I haven’t seen any kind of mentions about this in the docs.

So what I would like to do:

  • I would like to release a paid plugin
  • for this, I have to have <product-descriptor /> in the plugin.xml
  • but when I am just playing around and execute it with the runIde, I would like to just run it, without seeing the “Manage Licenses” dialog

The best would be to have some kind of runIdeWithoutLicenseCheck, but I have no idea how to create it properly. It takes so much work and hacking I am assuming I am doing something against Jetbrains’ idea on what runIde is or how I am supposed to use it.

I just don’t want to uncomment and undo the tag in the plugin.xml each time I use runIde and when I commit to git.

What I’ve tried so far is to create an action that changes the plugin.xml, but that seems to have no effect on the final output, even though the file itself is changed:

val myPluginXmlPatch by tasks.registering {
    dependsOn("patchPluginXml")

    doLast {
        val file = tasks.named<org.jetbrains.intellij.platform.gradle.tasks.PatchPluginXmlTask>("patchPluginXml")
            .get()
            .outputFile
            .asFile
            .get()

        val patchedXml = file.readText()
            .replace(
                Regex("""(?s)\s*<product-descriptor\b[^>]*?/>"""),
                "",
            )
        file.writeText(patchedXml)

        logger.lifecycle("Patched plugin.xml | ${file.absolutePath}")
    }
}

tasks.named("processResources") {
    dependsOn(myPluginXmlPatch)
}

Any help would be appreciated.

Instead, you can remove the product descriptor from your plugin.xml, then add it programmatically via your build.gradle.kts:

intellijPlatform {
  pluginConfiguration {
    if (paidPlugin) {
      productDescriptor {
        // this will create and populate the product-descriptor tag in plugin.xml (in the generated plugin archive)
        code = "..."
        releaseDate = "..."
        releaseVersion = "..."
        optional = false // or true for freemium plugin
      }
    }
  }
}
2 Likes

Thanks! This was a step forward in the right direction, but paidPlugin was still kinda tricky to specify.


For anyone struggling with this in the future, this is how I solved it:

In build.gradle.kts:

val licenseRequired: Boolean
    get() = !project.hasProperty("noLicense")

This ensures that whenever the runIde is executed with -PnoLicense flag (flag should be in the run command and NOT Environment Variables, since it is used at build time), the build script will have access to it.

This way I can conditionally add productDescriptor (just as Jonathan said):

intellijPlatform {
    pluginConfiguration {
        version = providers.gradleProperty("pluginVersion")

        if (licenseRequired) {
            productDescriptor {
                code = "CODE"
                releaseDate = "20250411"
                releaseVersion = "20250"
                optional = false
            }
        }
    }
}

Then I added generateBuildConfig as well, because I also need checks in my codebase.

kotlin {
    sourceSets.main {
        kotlin.srcDir("build/generated/sources/example")
    }
}

val generateBuildConfig by tasks.registering {
    // The file should be regenerated when this value changes, task should not be cached
    val licenseRequired = licenseRequired
    inputs.property("licenseRequired", licenseRequired)

    val outputDir = layout.buildDirectory.dir("generated/sources/example").get().asFile
    val packageName = "com.example"

    val content = """
        |package $packageName
        |
        |object BuildConfig {
        |    const val LICENSE_REQUIRED: Boolean = $licenseRequired
        |}
    """.trimMargin()

    outputs.dir(outputDir)

    doLast {
        val file = File(outputDir, "com/example/BuildConfig.kt")
        file.parentFile.mkdirs()
        file.writeText(content)
        logger.lifecycle("Generated BuildConfig.kt with LICENSE_REQUIRED = $licenseRequired")
    }
}

tasks.named("compileKotlin") {
    dependsOn(generateBuildConfig)
}