Skip to content

Gradle plugin to automate uploading JetBrains IDE plugins to a private repository and maintaining the plugin entry in updatePlugins.xml

License

MIT, Apache-2.0 licenses found

Licenses found

MIT
LICENSE
Apache-2.0
jetbrains-license.txt
Notifications You must be signed in to change notification settings

brian-mcnamara/plugin_uploader

Repository files navigation

Gradle Plugin Portal

IntelliJ plugin uploader

A gradle plugin to automate uploading an IntelliJ plugin and updating updatePlugins.xml hosted on a private repository, including S3-compatible stores.

Usage

buildscript {
    repositories {
        gradlePluginPortal()
    }
}

plugins {
    id "dev.bmac.intellij.plugin-uploader" version "1.3.5"
}

generateBlockMap {
  // Depend on either signPlugin or buildPlugin, depending on which task provides the file in the uploadPlugin
  dependsOn(project.tasks.named("signPlugin"))
}

uploadPlugin {
    def signPluginTask = project.tasks.named("signPlugin").get() as SignPluginTask
    // Get the plugin distribution file from the signPlugin task provided from the gradle-intellij-plugin
    def archive = signPluginTask.outputArchiveFile.asFile
    // If you do not wish to sign the plugin, you can use the buildPlugin output instead and specify `archive.archivePath` for the file argument
    // def archive = project.tasks.buildPlugin.get().archiveFile
    
    // For security, do not hard code usernames or passwords in source control, instead load them through the gradle properties:
    // <code> findProperty('some.gradle.property') as String </code>
    // or through Environment variables:
    // <code> System.getenv('SOME_ENVIRONMENT_VARIABLE') </code>
    def username = "exampleUsername" 
    def password = "examplePassword"
    url.set('https://repo.example.com/intellij/plugins/')
    pluginName.set('PluginName')
    file.set(archive.get())
    pluginId.set(project.group)
    version.set(project.version)
    pluginDescription.set(file('description.txt').text)
    changeNotes.set(file('change-notes.txt').text)
    sinceBuild.set("211")
    // Example for Basic type authentication
    authentication.set('Basic ' + new String(Base64.encoder.encode(("$username:$password").bytes)))
}

Configuration

Attributes Values
url - The url plus path of the repository to post the plugin to Required: true
Acceptable Values: Any URL, for example:
  • https://repo.example.com/intellij/plugins
  • http://repo.example.com:4443
pluginName - The plugin name to be used in the upload path such that url + pluginName is the folder the plugin will be uploaded to

Note: Name will be escaped when used as the upload path
Required: true
Acceptable Values: Any String
file - The file to be uploaded to the repo under url + pluginName + file.getName() Required: true
Acceptable Values: A existing file path, ideally should be set via project.tasks.buildPlugin as Zip which grabs the file from the IntelliJ gradle plugin
pluginId - Plugin Id used to match in the updatePlugins.xml Required: true
Acceptable Values: Any String
version - Plugin version used to update updatePlugins.xml Required: true
Acceptable Values: Any String
pluginDescription - Plugins description to be used in updatePlugins.xml Required: false
Default: none
Acceptable Values: Any String
changeNotes - Plugins change notes to be used in updatePlugins.xml Required: false
Default: none
Acceptable Values: Any String
sinceBuild - Plugins minimum required IDE version.
See Multi-versioning for more info.

Note: This should match the version specified in plugin.xml. The IDE will still validate the version in plugin.xml if this is excluded, but will not be until its been downloaded.
Required: false (required if using multi-versioning)
Default: none
Acceptable Values: A valid build number. See Build Number Ranges for more info.
untilBuild - Plugins max allowed IDE version.

Note: This should match the version specified in plugin.xml. The IDE will still validate the version in plugin.xml if this is excluded, but will not be until its been downloaded.
Required: false
Default: none
Acceptable Values: A valid build number. See Build Number Ranges for more info.
authentication - Authentication string used to publish files to the private repo. Will be used as the authorization header Required: false
Default: none
Acceptable Values:
  • Basic [authenticationString]
  • Bearer [bearerToken]
updateFile - Overrides the default updatePlugins.xml file name.

Note: See Publishing a Plugin to a Custom Plugin Repository for more information about updatePlugins.xml
Required: false
Default: updatePlugins.xml
Acceptable Values: Any String
updatePluginXml - Gates whether updatePlugins.xml is updated. Required: false
Default: true
Acceptable Values: true / false
repoType - Sets the type of repository operations to use. Required: false
Default: REST_POST
Acceptable Values:
  • REST_POST
  • REST_PUT
  • S3
absoluteDownloadUrls - deprecated: see downloadUrlPrefix
Use absolute url to the plugin download in update plugins xml over relative paths.
Required: false
Default: false
Acceptable Values: true / false
downloadUrlPrefix - Allows specifying the download url prefix to use over the default relative path. Required: false
Default: none
Acceptable Values: A URL prefix, for example:
  • https://repo.example.com/intellij/plugins
  • /intellij/plugins

    Supported repo types

    This plugin supports standard REST style repositories (Nexus, artifactory, etc) which accept uploads via POST/PUT requests. As of version 1.3.0, the plugin now supports Amazon S3 compatible stores as well.

    S3

    S3 compatible repositories are supported with the repoType set to S3. Some requirements should be noted:

    • AWS S3 should use virtual-hosted-style endpoints as the url, for example https://bucket-name.s3.Region.amazonaws.com/folder
    • non-AWS S3 endpoints need to specify the bucket name as the userinfo in the url, for example https://[email protected]/folder
    • Any path added to the url will be the directory structure under the bucket
    • Authentication can be specified by any means accepted by the aws sdk or can be passed into the authentication as a colon (:) separated list of access key, secret key, or access key, secret key, session token.

    Multi-versioning

    As of version 1.2.0, multiple plugin entries with the same ID can be added to the updateFile file as long as the since-build and until-build don't overlap. This is available since IDEA version 193.2956.37 (2019.3) which added entry-filtering using since and until build on each entry.

    The gradle plugin will check if the current upload, or an existing entry on the repository, has a since-build set before 193.2956.37 (or is not set), which prevents multiple entries from being added to ensure compatibility for the older IDEA versions.

    Otherwise, multi-versioning is enabled which will update an existing entry if the since-build matches otherwise a new entry is created and existing entries until-build are updated ensuring no overlap occurs.

    For best experience, it is recommended to always provide a valid build version to the sinceBuild parameter and to exclude the untilBuild parameter as this plugin will take care of adding until-build when new entries are uploaded. It should be noted, specifying untilBuild is possible while using multi-version, however the until-build version may be changed at a later time to a lower build version (for example, if a new entry specifies a since-build which is before the current entries until-build, the until-build will be updated to a build before the new entries since-build)

    Updating a local file-based updatePlugins.xml

    A task is registered as part of this plugin which can be used to update a file based updatePlugins.xml This can be useful when hosting plugins in source control over a dedicated repository.

    Usage

    task updateLocalPluginXml(type:dev.bmac.gradle.intellij.UpdateXmlTask) {
      updateFile.set(file('updatePlugins.xml'))
      downloadUrl.set('http://example.com/plugins/pluginFile.zip')
      pluginName.set('PluginName')
      pluginId.set(project.group)
      version.set(project.version)
      pluginDescription.set(file('description.txt').text)
      changeNotes.set(file('change-notes.txt').text)
      sinceBuild.set("211")
    }

    Notes

    This plugin uses a lock file to prevent concurrent modifications to the updatePlugins.xml file. While the lock file will be cleaned up, it could be left behind if the process is forcefully interrupted requiring the lock to be deleted manually. The lock can be found in the url root and is named updatePlugins.xml.lock (lock file name depends on updateFile)

    As of 1.3.0, a check will be performed to prevent replacing an existing release. This only checks updatePlugins.xml versions, so any versions not in this file will be allowed to be replaced. This can be disabled using dev.bmac.pluginUploader.skipReleaseCheck system property set to true

    Plugin Signing

    As of 2021.2 plugin signature are being checked during install. Private plugin can use plugin signing but require the signPlugin task be implemented and public/private keys be used to sign. While not required to use this plugin, it is recommended.

    License

    Most of this project is covered under the MIT license - located in the LICENSE file, with certain portions covered by Apache 2 license; all of which are clearly marked in a comment at the top of the file(s).

    About

    Gradle plugin to automate uploading JetBrains IDE plugins to a private repository and maintaining the plugin entry in updatePlugins.xml

    Topics

    Resources

    License

    MIT, Apache-2.0 licenses found

    Licenses found

    MIT
    LICENSE
    Apache-2.0
    jetbrains-license.txt

    Stars

    Watchers

    Forks

    Languages