如何将我的插件发布到插件门户?

注意:如果您正在使用Gradle 8(或更高版本)或插件版本为1.0(或更高),请切换到此页面的较新版本

注意:如果您之前通过Bintray发布了Gradle插件,请阅读此信息

注意:在发布插件之前,请确保您同意使用条款

门户设置

创建账户。

您可以通过注册页面快速轻松地创建新账户。

您可以使用同一个账户发布任意数量的插件。

创建API密钥。

登录后,您可以通过个人资料页面的“API密钥”标签获取您的API密钥。

您可以使用同一个API密钥发布任意数量的插件。

本地设置

创建API密钥后,您的个人资料页面中的“API密钥”标签将提供可以复制并粘贴到Gradle用户属性文件中的代码片段。

Gradle用户属性文件的默认位置是$USER_HOME/.gradle/gradle.properties,其中$USER_HOME代表您的用户主目录。

注意:插件发布插件还包括一个名为“login”的实验性任务,它是插件发布插件的一部分,可以自动化此步骤。

发布

插件发布插件提供了上传插件到插件门户的任务。您还可以使用它来发布将来插件的新版本。此插件不是Gradle分发的一部分,但本人在插件门户上托管。

配置完成后,您只需运行插件构建中的publishPlugins任务即可发布插件。有关详细信息,请参阅Gradle插件发布文档。请注意选择与您实际使用的Gradle版本匹配的版本,但请注意,从v7.6开始,Gradle手册关注更现代的插件版本,即1.0或更高。

元数据

从历史上看,有多种方法可以生成Gradle插件的发布元数据(例如Maven GAV坐标,即分组、工件、版本)

  • 插件发布插件有默认方法从插件ID和版本计算GAV
  • 可以使用特殊的mavenCoordinates块来覆盖上述默认值
  • 整个过程可以委托给Maven发布插件

在插件发布插件的未来版本中,将发布元数据生成委托给Maven发布插件将是首选(并且是强制性的)选项,因此我们将重点关注此文档及其示例。

示例

build.gradle.kts(Kotlin)

// First, apply the publishing plugin
plugins {
  // Apply the Java Gradle plugin development plugin to add support for developing Gradle plugins
  `java-gradle-plugin`
  // Alternatively apply other plugins, e.g. the kotlin plugin for a plugin written in Kotlin
  // or the groovy plugin if the plugin uses Groovy

  // Apply the Plugin Publish Plugin to make plugin publication possible
  id "com.gradle.plugin-publish" version "1.2.1"

  // Apply the Maven Publish Plugin to have it generate the publication metadata
  `maven-publish`
}

// 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"

// Use java-gradle-plugin to generate plugin descriptors and specify plugin ids
gradlePlugin {
  plugins {
    create("greetingsPlugin") {
      id = "io.github.johndoe.greeting"
      implementationClass = "io.github.johndoe.gradle.GreetingPlugin"
    }
    create("goodbyePlugin") {
      id = "io.github.johndoe.goodbye"
      implementationClass = "io.github.johndoe.gradle.GoodbyePlugin"
    }
  }
}

pluginBundle {
  // These settings are set for the whole plugin bundle
  website = 'https://github.com/johndoe/GradlePlugins'
  vcsUrl = 'https://github.com/johndoe/GradlePlugins'

  // tags and description can be set for the whole bundle here, but can also
  // be set / overridden in the config for specific plugins
  description = "Greetings from here!"

  // The plugins block can contain multiple plugin entries. The name for
  // each plugin block below (greetingsPlugin, goodbyePlugin)does not
  // affect the plugin configuration, but they need to be unique for each plugin.

  // Plugin config blocks can set the displayName, description and tags for
  // each plugin. displayName is mandatory. If no tags or description are set
  // the tags or description from the pluginBundle block will be used,
  // but they must be set in one of the two places.

  (plugins) {
    "greetingsPlugin" {
      // id is captured from java-gradle-plugin configuration
      displayName = "Gradle Greeting plugin"
      tags = listOf("individual", "tags", "per", "plugin")
      version = "1.2"
    }

    "goodbyePlugin" {
      // id is captured from java-gradle-plugin configuration
      displayName = "Gradle Goodbye plugin"
      description = "Override description for this plugin"
      tags = listOf("different", "for", "this", "one")
      version = "1.3"
    }
  }
}

build.gradle(Groovy)

// First, apply the publishing plugin
plugins {
  // Apply the Java Gradle plugin development plugin to add support for developing Gradle plugins
  id 'java-gradle-plugin'
  // Alternatively apply other plugins, e.g. the kotlin plugin for a plugin written in Kotlin
  // or the groovy plugin if the plugin uses Groovy

  // Apply the Plugin Publish Plugin to make plugin publication possible
  id "com.gradle.plugin-publish" version "1.2.1"

  // Apply the Maven Publish Plugin to have it generate the publication metadata
  id 'maven-publish'
}

// 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'

// Use java-gradle-plugin to generate plugin descriptors and specify plugin ids
gradlePlugin {
  plugins {
    greetingsPlugin {
      id = 'io.github.johndoe.greeting'
      implementationClass = 'io.github.johndoe.gradle.GreetingPlugin'
    }
    goodbyePlugin {
      id = 'io.github.johndoe.goodbye'
      implementationClass = 'io.github.johndoe.gradle.GoodbyePlugin'
    }
  }
}

pluginBundle {
  // These settings are set for the whole plugin bundle
  website = 'https://github.com/johndoe/GradlePlugins'
  vcsUrl = 'https://github.com/johndoe/GradlePlugins'

  // tags and description can be set for the whole bundle here, but can also
  // be set / overridden in the config for specific plugins
  description = 'Greetings from here!'

  // The plugins block can contain multiple plugin entries. The name for
  // each plugin block below (greetingsPlugin, goodbyePlugin)does not
  // affect the plugin configuration, but they need to be unique for each plugin.

  // Plugin config blocks can set the displayName, description and tags for
  // each plugin. displayName is mandatory. If no tags or description are set
  // the tags or description from the pluginBundle block will be used,
  // but they must be set in one of the two places.

  plugins {
    greetingsPlugin {
      // id is captured from java-gradle-plugin configuration
      displayName = 'Gradle Greeting plugin'
      tags = ['individual', 'tags', 'per', 'plugin']
    }

    goodbyePlugin {
      // id is captured from java-gradle-plugin configuration
      displayName = 'Gradle Goodbye plugin'
      description = 'Override description for this plugin'
      tags = ['different', 'for', 'this', 'one']
    }
  }
}

审批

当一个新插件发布时,它将经过人工审查流程。这通常只发生在初始版本时。Gradle工程师将检查元数据,并决定是否使其在门户上可见或要求对其进行更改。请注意,任何对Maven组或插件ID的更改都将在审批过程中再次触发。

所有插件都必须遵守以下规则

插件必须具备某些功能

“Hello world”类型提交,或任何其他不具备某些最基本有用功能的插件将被拒绝。

插件应提供文档

应该有一个描述来说明插件的目的。

标签应符合插件所涉及的类别。

项目URL应指向文档、项目源代码或两者都指向。

VCL URL应指向插件源代码。理想情况下,插件应该是开源的,除非有充分的理由不这么做。专有插件的作者应联系我们

插件ID应可追溯到作者

如果GitHub用户johndoe发布了一个名为myplugin的插件,那么一个可接受的插件ID将是io.github.johndoe.myplugin。注意:com.github已被停止作为前缀,以符合Maven Central政策

另一个例子是一个企业插件,比如来自mybusiness.com的;那么插件ID应类似于com.mybusiness.pluginname。在这种情况下,作者应通过企业账户/电子邮件地址提交插件。我们更喜欢集团(相对于个人)地址,以突出组织(或其子分组)是插件的所有者。

如果我们不能将域名链接,我们将要求提供证据,以DNS条目中添加的TXT记录的形式。

仅应发布最终版本

我们将拒绝SNAPSHOT版本,因为无论如何都是无法覆盖它们的。

插件应从非分叉的存储库发布

同一插件不应在门户上有多个版本。插件开发者应尝试与原始作者合作,以整合他们的更改/改进。某些例外是可以接受的,例如当原始存储库被遗弃,并且不接受贡献时。

故障排除

发布失败

这里描述的问题发生在插件发布过程中,通常导致发布流程失败。

组ID不能以gradle.plugin开头

这种发布拒绝最可能发生的情况是当插件发布插件被使用而无需依赖Maven发布插件来生成发布元数据时。在这种情况下,插件发布插件本身正在向插件的M2 GAV添加此前缀,服务器不再接受它。

首选的解决方案是简单地包括示例中展示的maven-publish插件。

如果由于某些原因您不能使用此解决方案,那么您的另一种选择是在pluginBundle块内部使用mavenCoordinates块来覆盖M2 GAV值,如下所示

pluginBundle {
  mavenCoordinates {
    groupId = "org.myorg"
    artifactId = "greeting-plugins"
    version = "1.4"
  }
}

GitHub组ID前缀不能是com.github

GitHub在2013年(见此) introduceed了一个新的,专属的域(github.io)用于其页面服务。今年他们停止自动从旧的历史域(github.com)转发到这个新域。

Maven Central随后宣布他们将为此做出反应,并宣布他们不再允许com.github作为有效的组ID前缀(见此)。

Gradle插件的门户网站也采用了这项规则,因此在插件配置中请使用io.github前缀。

插件版本不能是SNAPSHOT

插件门户网站不允许插件以SNAPSHOT结尾的版本发布,因为它们可能不会按预期行为。所有版本都被视为固定版本,因此相同版本的重新发布是不可能的,因此快照的概念也就毫无意义。

请使用固定版本。

您的不同工件具有相同的哈希值

插件门户网站的一个错误导致它错误地处理具有工件之间哈希冲突的发布。修复此错误需要更改协议,因此必须使用版本1.0+以修复此问题。请升级

批准拒绝

这里描述的问题发生在插件第一个版本成功发布之后,如果插件被门户网站管理员标记为需要手动审批,并且他们以各种原因拒绝该插件,他们将通过电子邮件通知您拒绝的原因。

无法建立所有权

这种问题的典型场景是当一个插件从一个GitHub(或类似)仓库发布,但GitHub账户无法与执行发布的插件门户网站账户链接。解决方案是使用一个与GitHub账户链接的插件门户网站账户(您可以通过GitHub账户登录插件门户网站),或者将支持您插件门户网站账户的电子邮件地址在GitHub账户上设置为公开可见。

另一个典型场景是,当属于某个组织机构的插件正在发布,但发布插件门户网站账户无法与该组织链接时。在这种情况下,您可能需要通过在不属于该组织的域主机上添加一些随机的TXT DNS记录来证明您对该组织域的主权。门户网站管理员将与您联系并提供确切的记录。

插件基于分叉的仓库

同一插件有多个变体,从分叉的、可能分叉的仓库发布,可能会导致很多混淆,所以这通常是不被鼓励的。如果您发现自己处于这种情况下,我们鼓励您将您的贡献作为Pull Requests提交给原始仓库。

这一规则的例外是废弃的仓库,确实,在这种情况下,分叉并获取所有权是唯一的选择。

插件缺少公开文档

当出现此类问题时,一个典型的情况是插件发布期间提供的网站或VCS URL指向一个损坏或无法访问的目的地。另一个情况是,URL指向例如一个公共GitHub仓库,但没有文档存在(空的READMME文件)。

缺乏文档的问题在于它使得社区采用插件的可能性非常低。

解决这个问题的方法是让文档可供公众查看,或者,如果您的插件实际上是私有的,考虑将其发布到私有工件仓库。

完成任务!

您的插件现在是Gradle插件门户网站的一部分,可以供全球的Gradle用户使用。

感谢您的贡献。

所有插件都需要插件门户网站维护者的手动接受,发布后不会立即提供。这仅适用于新插件的第一个版本。插件发布插件将在您发布时告诉您您的插件是否待接受。

如果您的插件在可以接受之前需要更改,您将以与您的账户关联的电子邮件地址收到通知。当您的插件被接受时,您也将收到通知。