How do I publish my plugin to the Plugin Portal using version 1.0+?

NOTE: If you are using an older (0.X) version of the plugin, please switch to the older version of this page.

NOTE: If you have previously published Gradle plugins via Bintray, please read this information.

Portal Setup

Create an account.

You can quickly and easily create a new account via the registration page.

You can use the same account to publish as many plugins as you like.

Create an API key.

Once logged in, you can get your API key via the “API Keys” tab of your profile page.

You can use the same API key to publish as many plugins as you like.

Local Setup

Once you've created an API key, the “API Keys” tab of your profile page will provide a snippet that you can copy & paste into your Gradle user properties file.

The default location for the Gradle user properties file is $USER_HOME/.gradle/gradle.properties, where $USER_HOME refers to your user home directory.

NOTE: There is also an experimental task, “login“, that is part of the plugin publishing plugin, which automates this step.

Publication

The Plugin Publishing plugin provides tasks that upload your plugin to the Plugin Portal. It can also be used to publish updated versions of your plugin. This plugin is not part of the Gradle distribution but is itself hosted on the Plugin Portal.

Once configured, your plugin can be published by simply running the publishPlugins task of your plugin's build. Detailed instructions can be found in the Gradle docs for plugin publishing. Take care to select the version matching the actual Gradle version you are using, but not older than v7.6 (that is the version when the manual starts focusing on more modern versions of the plugin, ie. 1.0 or higher).

Limitations

Starting from version 1.0.0, the Plugin Publish plugin is only compatible with Gradle 4.10.3 or later (due to relying on maven publication).

Furthermore, when using the Shadow plugin and relying on its interactions with the Plugin Publish plugin, a minimum Gradle version of 6.0.1 is required for the two plugins to work together correctly (see below).

Helper plugins

Plugin Development plugin

Starting with version 1.0.0, the Plugin Development plugin becomes a mandatory component of the Plugin Publish plugin and is automatically applied with it. Further info on how it interacts with the Maven Publish plugin (also auto-applied by the Plugin Publish plugin) can be found here.

Maven Publish plugin

Starting with Plugin Publish plugin v1.0.0 the only supported way of generating the publication metadata (think Maven GAV coordinates, i.e. group, artifact, version) for Gradle plugins is via the Maven Publish plugin. In fact, the `maven-publish` plugin is auto-applied when applying `plugin-publish`.

The simultaneous presence of the Maven Publish and Plugin Development plugins, both auto-applied, triggers the configuration of specific Maven publications which will be published to the Plugin Portal. More information on it can be found here.

Signing plugin

Starting with version 1.0.0 the Plugin Publish plugin can automatically sign the artifacts it publishes to the Portal. All artifact included in the main & marker Maven publications will be included, not just jars, POMs & Gradle Module Metadata files. This functionality is turned on by simply applying the Signing plugin.

Shadow plugin

Starting with version 1.0.0 the Plugin Publish plugin can automatically interact with the com.github.johnrengelman.shadow plugin, if applied. It will automatically publish the jar produced by the shadowJar task, as the main artifact. Note that this interaction requires the usage of Gradle v6.0.1 or later, in order to work properly.

Examples

Plugin Publish plugin v1.0.0 simplifies the configuration of plugin publishing by merging the `pluginBundle` block into the `gradlePlugin` one.

These simplifications however require backing support in the Gradle API, so are only available when using the Plugin Publish Plugin with Gradle v7.6 or later. This version is however not yet released. That is why the links to the Gradle manual you find on this page refer to the "nightly" build of the manual.

With older Gradle versions the configuration improvements are more limited, please rely on the following examples for what is available (as opposed to the "nightly" manual, which will also contain more advanced samples that become available with Gradle v7.6).

build.gradle

// First, apply the publishing plugin
plugins {
  // Apply the Plugin Publish plugin to make plugin publication possible.
  // The Plugin Publish plugin will in turn auto-apply the Gradle Plugin Development Plugin (java-gradle-plugin)
  // and the Maven Publish plugin (maven-publish).
  id 'com.gradle.plugin-publish' version '1.0.0'

  // Apply the signing plugin (signing) if you want the published artifacts of your plugin be automatically signed.

  // Apply the shadow plugin (com.github.johnrengelman.shadow) if you want to automatically make the main jar
  // of your plugin be a fat one, shadowing its dependencies.

  // Apply more plugins, if needed, for example the kotlin plugin for a plugin written in Kotlin
  // or the groovy plugin if the plugin uses Groovy.
}

// If your plugin has any external dependencies, users might need to declare repositories in their
// build settings so that Gradle can download them when using the plugins DSL.
repositories {
  mavenCentral()
}

// The project version will be used as your plugin version when publishing.
version = '1.2'
group = 'io.github.johndoe'

// Specify plugin properties that apply to the whole publishing bundle (ie. all plugins in the current publication).
pluginBundle {  // Removed in Gradle 8+
  website = 'https://github.com/johndoe/GradlePlugins'
  vcsUrl = 'https://github.com/johndoe/GradlePlugins'

  // Individual descriptions for plugins can be set via the java-gradle-plugin, see below.
  description = 'Greetings from here!'

  tags = ['tags', 'for', 'all', 'plugins']

  // Individual tags for published plugins; overrides bundle tags for the mentioned plugins.
  // The keys used to specify the plugins must match the names of the blocks in 'gradlePlugin.plugins' (see below).
  pluginTags = [
          goodbyePlugin: ['individual', 'tags', 'per', 'plugin'],
          someOtherPlugin: ['some', 'other', 'tags']
  ]
}

// Use java-gradle-plugin to generate plugin descriptors and override individual plugin properties.
// The names of the blocks inside 'plugins' need to be unique, they will identify the plugins being configured.
// 'id', 'implementationClass' and 'displayName' are mandatory.
// 'description' is optional and will override whatever description has been specified at bundle level, but
// in the end a description must be set for each plugin at some level.
gradlePlugin {
  plugins {
    greetingsPlugin {
      id = 'io.github.johndoe.greeting'
      implementationClass = 'io.github.johndoe.gradle.GreetingPlugin'
      displayName = 'Gradle Greeting plugin'
    }
    goodbyePlugin {
      id = 'io.github.johndoe.goodbye'
      implementationClass = 'io.github.johndoe.gradle.GoodbyePlugin'
      displayName = 'Gradle Goodbye plugin'
      description = 'Gradle plugin to say goodbye!'
    }
  }
}

build.gradle.kts

// First, apply the publishing plugin
plugins {
  // Apply the Plugin Publish plugin to make plugin publication possible
  // The Plugin Publish plugin will in turn auto-apply the Gradle Plugin Development Plugin (java-gradle-plugin)
  // and the Maven Publish plugin (maven-publish)
  id("com.gradle.plugin-publish") version "1.0.0"

  // Apply the signing plugin (signing) if you want the published artifacts of your plugin be automatically signed.

  // Apply the shadow plugin (com.github.johnrengelman.shadow) if you want to automatically make the main jar
  // of your plugin be a fat one, shadowing its dependencies.

  // Apply more plugins, if needed, for example the kotlin plugin for a plugin written in Kotlin
  // or the groovy plugin if the plugin uses Groovy.
}

// If your plugin has any external dependencies, users might need to declare repositories in their
// build settings so that Gradle can download them when using the plugins DSL.
repositories {
  mavenCentral()
}

// The project version will be used as your plugin version when publishing.
version = "1.2"
group = "io.github.johndoe"

// Specify plugin properties that apply to the whole publishing bundle (ie. all plugins in the current publication).
pluginBundle {  // Removed in Gradle 8+
  website = "https://github.com/johndoe/GradlePlugins"
  vcsUrl = "https://github.com/johndoe/GradlePlugins"

  // Individual descriptions for plugins can be set via the java-gradle-plugin, see below.
  description = "Greetings from here!"

  tags = listOf("tags", "for", "all", "plugins")

  // Individual tags for published plugins; overrides bundle tags for the mentioned plugins.
  // The keys used to specify the plugins must match the names of the blocks in 'gradlePlugin.plugins' (see below).
  pluginTags = mapOf(
          "goodbyePlugin" to listOf("individual", "tags", "per", "plugin"),
          "someOtherPlugin" to listOf("some", "other", "tags")
  )
}

// Use java-gradle-plugin to generate plugin descriptors and override individual plugin properties.
// The names of the blocks inside 'plugins' need to be unique, they will identify the plugins being configured.
// 'id', 'implementationClass' and 'displayName' are mandatory.
// 'description' is optional and will override whatever description has been specified at bundle level, but
// in the end a description must be set for each plugin at some level.
gradlePlugin {
  plugins {
    create("greetingsPlugin") {
      id = "io.github.johndoe.greeting"
      implementationClass = "io.github.johndoe.gradle.GreetingPlugin"
      displayName = "Gradle Greeting plugin"
    }
    create("goodbyePlugin") {
      id = "io.github.johndoe.goodbye"
      implementationClass = "io.github.johndoe.gradle.GoodbyePlugin"
      displayName = "Gradle Goodbye plugin"
      description = "Gradle plugin to say goodbye!"
    }
  }
}

Approval

When a new plugin is published it will go through a manual review process. This usually happens only for the initial version. NOTE: Any change of Maven group or plugin ID will cause the approval process to be triggered again. The plugin publishing plugin will tell you if your plugin is pending acceptance when you publish.

A Gradle engineer will inspect the metadata and decide whether to make it visible on the Portal or request changes to it. If your plugin requires changes before it can be accepted, you will be contacted via the email address associated with your account. You will also receive an email when your plugin is accepted.

All plugins must adhere to the following rules:

Plugins must have some functionality

"Hello world" type submissions, or any other plugin not having some minimal useful functionality will be rejected.

Plugins should be documented

There should be a description specifying the intent of the plugin.

Tags should be set to describe the categories the plugin covers.

The project URL should point to the documentation, to the project sources, or both.

The VCL URL should point to the plugin sources. Plugins should ideally be open-source, unless there is a good reason to do otherwise. Proprietary plugin authors should reach out to us.

Plugin IDs should trace back to the author

If a GitHub user johndoe publishes a plugin called myplugin, then an acceptable plugin ID would be io.github.johndoe.myplugin. NOTE: com.github is no longer accepted as a prefix, in order to align with the Maven Central policy.

Another example would be a corporate plugin, let's say from mybusiness.com; then the plugin ID should look like com.mybusiness.pluginname. In this case, the author should also submit the plugin via a corporate account/email address. We prefer group (as opposed to individual) addresses, to highlight that the organization (or a sub-group of it) is the owner of the plugin.

If we cannot link to the domain, we will ask for proof, in the form of a TXT record added to the DNS entry.

Only final versions should be published

We will reject SNAPSHOT versions because it's not possible to override them anyways.

Plugins should be published from non-forked repositories

There shouldn't be multiple variants of the same plugin published on the Portal. Plugin developers should try to work with the original author(s) to get their changes/improvements integrated. Some exceptions are acceptable, for example when the original repository is abandoned, and it doesn't accept contributions.

Troubleshooting

Publication Failed

The problems described here happen during plugin publication and usually lead to the failure of the publication process.

The GitHub group ID prefix can't be com.github

Github has introduced a new, dedicated domain (github.io) for it’s Pages service, back in 2013 (see here). This year they have stopped automatically forwarding from the old, legacy domain (github.com) to this new one.

Maven Central has then announced that they will react to this and that they will no longer allow com.github as a valid group ID prefix (see here).

The Gradle Plugin Portal has also adopted this convention, so please use the io.github prefix in your plugin configurations.

Plugin version can't be SNAPSHOT

The Plugin Portal doesn't allow plugins to be published with versions ending in SNAPSHOT, because they wouldn't behave as expected. All versions are considered fixed, so re-publishing of the same version wouldn't be possible, thus the whole concept of snapshots would be meaningless.

Please use fixed versions instead.

Approval Denied

The problems described here happen after the successful publication of the first version of a plugin, if the plugin gets flagged for manual approval by the Portal administrators, and they reject the plugin for various reasons. They will send you an email with the reasons for the rejection.

Ownership can't be established

One typical scenario of this problem is when a plugin gets published from a GitHub (or similar) repository, but the GitHub account can't be linked to the Plugin Portal account doing the publishing. The solution to this is to either use a Plugin Portal account linked to a GitHub account (you can log into the Plugin Portal via your GitHub account) or to make the email address backing your Plugin Portal account publicly visible on your GitHub account.

Another typical scenario is when a plugin belonging to an organization is being published, but the publishing Plugin Portal account can't be linked to the organization. In such cases you might be asked to prove ownership of the organization's domain by adding some random TXT DNS record to your organization's domain host. Portal administrators will contact you and provide you with the exact record.

Plugin is based on a forked repository

Having multiple variants of the same plugin, published from forked, potentially diverging repositories could lead to a lot of confusion, so it's generally not encouraged. If you find yourself in this situation, we encourage you to submit your contributions as Pull Requests to the original repository.

The exception to this rule are abandoned repositories, where indeed forking and taking ownership is the only option.

Plugin is lacking public documentation

One typical situation when this problem arises is when the website or VCS URLs provided during plugin publication point to a broken or inaccessible destination. Another one is when the URLs point to, for example a public GitHub repository, but there is no documentation there \ (empty README file).

The problem with the lack of documentation is that it makes the adoption of the plugin by the community very unlikely.

The solution to this problem is to either make the documentation publicly available, or, if your plugin is indeed private, consider publishing it to a private repository.

You're done!

Your plugin is now part of the Gradle Plugin Portal and can be put to use by Gradle users all over the world.

Thank you for contributing.