Convention based Cake scripts for building IntelliJ plugins.
- Cake.IntelliJ.Recipe
#load nuget:?package=Cake.IntelliJ.Recipe#load nuget:?package=Cake.IntelliJ.Recipe
Environment.SetVariableNames();
IntelliJBuildParameters.SetParameters(
context: Context,
buildSystem: BuildSystem,
sourceDirectoryPath: "./src",
title: "Best-Plugin-Ever",
repositoryOwner: "nils-a");
IntelliJBuildParameters.PrintParameters(Context);
ToolSettings.SetToolSettings(context: Context);
IntelliJBuild.Run();Please be aware, that Cake.IntelliJ.Recipe wraps a gradle build
and uses tasks from org.jetbrains.intellij gradle plugin.
It is advised to create the plugin from https://github.com/JetBrains/intellij-platform-plugin-template.
If you have questions, search for an existing one, or create a new discussion on the Cake GitHub repository, using the extension-q-a category.
The Cake target IntelliJAnalyze is run on every build and is used to run code analysis.
The default in this target is to run the following gradle tasks:
detekt, ktlintCheck, and verifyPlugin.
If for some reason this should be changed (e.g. for plugins that do not use detekt and ktlint but rather depend on something different),
the tasks to invoke can be configured using the intelliJAnalyzerTasks setting.
IntelliJBuildParameters.SetParameters(
// ... all other parameters ...
intelliJAnalyzerTasks: new[]{ "check", "verifyPlugin" }
);Settings with regard to publishing channels are:
pluginReleaseChannelwith a default of"Stable"pluginPreReleaseChannelwith a default of"Beta"pluginCiBuildChannelwith a default of"Alpha"shouldPublishPluginCiBuildswith a default offalsepluginChannelGradlePropertywith a default of"marketplaceChannel"
See Releases and PreReleases for their meaning.
The verbosity of running gradle has it's own setting: gradleVerbosity. (Default is set to GradleLogLevel.Default)
Keep in mind, that while setting Cake verbosity to diagnostic, secrets will still be secret.
However, setting gradle verbosity to GradleLogLevel.Debug will print out all secrets in the logs.
When publishing is automated, Twitter and Gitter messages can be created. To have them link to the plugin-page in the marketplace,
a setting of marketplaceId is needed. The marketplaceId can be fetched from the URL in the marketplace, e.g. for https://plugins.jetbrains.com/plugin/15698-test-rider, the marketplaceId is 15698-test-rider.
All other settings for Twitter, Gitter and such follow Cake.Recipe.
The gradle task runPluginVerifier runs the JetBrains plugin verifier.
This task is "mapped" to the Cake target Run-Plugin-Verifier which runs on CI builds.
If running on CI builds is not desired for any reason, the setting shouldRunPluginVerifier can be used to disable the run.
Example: Do not run the plugin verifier, if the build runs on Linux (e.g. beacuse the GitHub actions Linux runner does not have enough free space for the plugin verifier.)
IntelliJBuildParameters.SetParameters(
// ... all other parameters ...
shouldRunPluginVerifier: !IsRunningOnLinux()
);To publish the plugin to the JetBrains Marketplace a token is required.
The token must be supplied in an environment variable and is then picked up in the gradle build.
Default for plugins created from https://github.com/JetBrains/intellij-platform-plugin-template is to use the PUBLISH_TOKEN variable name.
Also, as with the "normal" gradle-based publishing, the first publish of the plugin must be made manually.
When creating a new recipe for a plugin that was created from https://github.com/JetBrains/intellij-platform-plugin-template the following changes have to be made:
The standard template makes use of the org.jetbrains.intellij gradle-plugin to update the <description> of the plugin.xml
automatically from the content of the Readme.md which is perfectly fine.
If the Readme.md were to be moved (say one folder up - to fit in with the recipe structure) that would needed fixing.
The default code in build.gradle.kts is:
// Extract the <!-- Plugin description --> section from README.md and provide for the plugin's manifest
pluginDescription(
closure {
File("./README.md").readText().lines().run {
val start = "<!-- Plugin description -->"
val end = "<!-- Plugin description end -->"
if (!containsAll(listOf(start, end))) {
throw GradleException("Plugin description section not found in README.md:\n$start ... $end")
}
subList(indexOf(start) + 1, indexOf(end))
}.joinToString("\n").run { markdownToHTML(this) }
}
)This should point to the new location of the Readme.md, e.g.:
// ...
File("../README.md").readText().lines().run {
// ...Alternatively, the whole code-block could be removed from build.gradle.kts and a <description> manually added to the plugin.xml.
Be aware, that the description is html with all entities encoded. (Something like <description><h3>This is the plugin!</h3></description>).
The standard template makes use of the org.jetbrains.changelog gradle-plugin to keep the Changelog.md updated with current version numbers and to copy the latest changes into the <change-notes> section of the plugin.xml on build.
Currently Cake.IntellJ.Recipe does not bridge the gap between release notes in GitHub releases (as preferred and automatically created by Cake.Recipe) and having the latest changes shown in the plugin (See Issue 12).
The suggestion is to place a link to the GitHub releases page inside the change-notes of plugin.xml.
For that, here are two parts inside build.gradle.kts which should be removed:
in patchPluginXml:
// Get the latest available change notes from the changelog file
changeNotes(
closure {
changelog.getLatest().toHTML()
}
)and in publishPlugin:
dependsOn("patchChangelog")And the change-notes in plugin.xml have to be added manually. Something like
<change-notes>
<a href="https://github.com/nils-a/test-rider/releases"><h3>See GitHub Releases</h3></a>
</change-notes>is suggested.
Original Cake.Recipe knows three types of releases:
- Releases (created by adding a tag to the main branch) will publish a release-package to the release package source (typically NuGet).
- Tagged PreReleases (created by adding a tag on a different (i.e. not the main) branch) will publish a preRelease-package to the release package source (typically NuGet).
- PreReleases generated by CI-builds will publish a preRelease-package to the other package sources (e.g. MyGet, Azure, GPR).
JetBrains Marketplace does not have the notion of preReleases per se. Also there are (short of creating a custom plugin repository) no alternatives to the JetBrains Marketplace.
The Marketplace however does have the notions of "channels". Channels are treated as separate repositories for all intents and purposes and only the default channel (named Stable) is browsable and searchable.
Cake.IntelliJ.Recipe has the following settings prepared for the above mentioned release-types:
pluginReleaseChannel(default:"Stable") as the name of the channel to publish releases to.pluginPreReleaseChannel(default"Beta") as the name of the channel to publish tagged preReleases to.pluginCiBuildChannel(default"Alpha") as the name of the channel to publish CI-builds to.
Be aware, that publishes to JetBrains marketplace are moderated so they will not be available to the public instantaneously.
Also, for the very same reason publishing CI builds is deactivated in the defaults. Use shouldPublishPluginCiBuilds (default false) to enable it.
To make this work, Cake.IntelliJ.Recipe will pass the selected channel to gradle via a project property.
The name of that property is set in pluginChannelGradleProperty (default: "marketplaceChannel") and it has to be picked up by the gradle task publishPlugin in build.gradle.kts.
The code
publishPlugin {
token(System.getenv("PUBLISH_TOKEN"))
// pluginVersion is based on the SemVer (https://semver.org) and supports pre-release labels, like 2.1.7-alpha.3
// Specify pre-release label to publish the plugin in a custom Release Channel automatically. Read more:
// https://jetbrains.org/intellij/sdk/docs/tutorials/build_system/deployment.html#specifying-a-release-channel
channels(pluginVersion.split('-').getOrElse(1) { "default" }.split('.').first())
}should be replaced with:
publishPlugin {
token(System.getenv("PUBLISH_TOKEN"))
channels(marketplaceChannel)
}additionally the line
val marketplaceChannel: String by projecthas to be added near the text line "// Import variables from gradle.properties file".
and also, inside the gradle.properties a default has to be supplied:
marketplaceChannel = developmentGenerally everything from Cake.Recipe applies here, too.
There are some modifications to be made to get gradle and/or java working correctly. Namely:
- Ensuring a
JAVA_HOMEenvironment variable that points to thejavaversion needed for building of the plugin - Caching
~/.gradle/cachesand~/.gradle/wrapper
TODO: Check why building on windows was so slow in the first tests.
To set the correct java version, use the following:
# Setup Java 1.8 environment which is needed to build
- name: Setup Java
uses: actions/setup-java@v1
with:
java-version: 1.8(Remark: choose java version 1.8, only if version 1.8 is what is needed to build your plugin.)
Additional caching of gradle is advised.
Also, (and only on GitHub Actions) the use of the Gradle Wrapper Validation Action
is advised to ensure only official versions of graldew are checked in.
# Validates the gradle wrappers and saves us from getting malicious PRs
- name: Gradle Wrapper Validation
uses: gradle/wrapper-validation-action@v1
# Cache Gradle dependencies
- name: Setup Gradle Dependencies Cache
uses: actions/cache@v2
with:
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-caches-${{ hashFiles('**/*.gradle', '**/*.gradle.kts', 'gradle.properties') }}
# Cache Gradle Wrapper
- name: Setup Gradle Wrapper Cache
uses: actions/cache@v2
with:
path: ~/.gradle/wrapper
key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/gradle/wrapper/gradle-wrapper.properties') }}AppVeyor builds on linux currently fail, due to #15
AppVeyor comes with multiple java versions (all based on openJDK) preinstalled.
To select between versions on linux, the stack definition can be used
stack: jdk 8To select between version on Windows, the JAVA_HOME needs to be manually set correctly. The Paths are documented
environment:
JAVA_HOME="C:\Program Files\Java\jdk1.8.0"(Remark: choose java version 1.8 (or 8), only if version 1.8 is what is needed to build your plugin.)
Additional caching of gradle is advised. Keep in mind though, that gradle caches can be quite large and that limitations might apply
cache:
- '%USERPROFILE%\.gradle\caches -> **\*.gradle, **\*.gradle.kts, gradle.properties'
- '%USERPROFILE%\.gradle\wrapper -> **\gradle\wrapper\gradle-wrapper.properties'Cake.IntelliJ.Recipe follows the Contributor Covenant Code of Conduct.
We accept Pull Requests. Please see the contributing file for how to contribute to Cake.IntelliJ.Recipe.
Small note: If editing the Readme, please conform to the standard-readme specification.
This project follows the all-contributors specification. Contributions of any kind welcome!
Thanks goes to these wonderful people (emoji key):
Nils Andresen 💻 |