Releases are published to JetBrains Marketplace by the Release workflow when a version tag is pushed. The build side is ready; the steps below are the ones only the maintainer can do, because they need a JetBrains account, a private key and repository secrets.
Sign in at https://plugins.jetbrains.com with a JetBrains Account and create a vendor profile (personal is enough).
plugin.xml declares the vendor as agadek with the URL https://github.com/agadek/markdown-review; change the
<vendor> element if the profile uses a different name.
Generate a private key and a self-signed certificate chain (from the plugin signing docs):
openssl genpkey -aes-256-cbc -algorithm RSA -out private_encrypted.pem -pkeyopt rsa_keygen_bits:4096
openssl rsa -in private_encrypted.pem -out private.pem
openssl req -key private.pem -new -x509 -days 365 -out chain.crt
Keep private_encrypted.pem and its password outside the repository (a password manager). The certificate is valid
for 365 days; set a reminder to renew it.
On the Marketplace profile, open My Tokens, generate a token and copy it right away (it is shown once).
| In the repository’s **Settings | Secrets and variables | Actions**, add: |
| Secret | Value |
|---|---|
CERTIFICATE_CHAIN |
base64 -i chain.crt |
PRIVATE_KEY |
base64 -i private.pem |
PRIVATE_KEY_PASSWORD |
the password given to openssl genpkey |
PUBLISH_TOKEN |
the Marketplace token |
The signing docs say the Gradle plugin detects and decodes Base64 values, which avoids multi-line secrets.
build.gradle.kts reads the same four names from environment variables, so a local
./gradlew signPlugin or publishPlugin works with them exported in the shell.
Marketplace accepts uploads from Gradle only after the plugin exists there, and the first version goes through moderation. With the four variables exported locally:
./gradlew signPlugin
Upload build/distributions/markdown-review-<version>-signed.zip on https://plugins.jetbrains.com/plugin/add,
fill in the license and source code fields (next section), add the screenshots from docs/screenshots/
(side-by-side-light.png, merged-light.png and their dark versions), and wait for approval. The page text comes from
<description> in plugin.xml and the change notes from CHANGELOG.md, the icon from pluginIcon.svg and pluginIcon_dark.svg.
Marketplace requires a license link for every plugin, free ones included. PolyForm Noncommercial is not an OSI license, so it is given as a custom license URL rather than picked from a list:
https://github.com/agadek/markdown-review/blob/main/LICENSE (or
https://polyformproject.org/licenses/noncommercial/1.0.0).https://github.com/agadek/markdown-review.plugin.xml already does, with a link to COMMERCIAL_LICENSE.md).pluginVersion in gradle.properties, for example 0.2.0-beta or 1.0.0../gradlew patchChangelog. It moves the entries under ## [Unreleased] in CHANGELOG.md to a new section
for pluginVersion with today’s date and leaves an empty [Unreleased] section. The build renders every released
section of CHANGELOG.md into the plugin’s change notes, so entries left under [Unreleased] do not reach
Marketplace. Merge to main.Tag the merge commit and push the tag:
git tag v0.2.0-beta
git push origin v0.2.0-beta
The workflow fails if the tag does not equal v<pluginVersion> or a secret is missing. It runs the tests, builds,
runs verifyPlugin, signs, attaches the signed zip to a GitHub release named after the tag, and then publishes to
Marketplace. The release is created before the upload, so it has the plugin zip even when the upload fails, for
example with “already contains version” when that version was uploaded by hand. The signed zip is also kept as a
workflow artifact.
Actions | Preview release | Run workflow builds, verifies and signs the current main (it needs the three signing
secrets, not PUBLISH_TOKEN) and attaches the signed zip to a GitHub pre-release tagged preview-<pluginVersion>.
Nothing goes to Marketplace, and the tag does not start with v, so the Release workflow does not run. The download
link stays the same for a version:
https://github.com/agadek/markdown-review/releases/download/preview-<version>/markdown-review-<version>-signed.zip.
Running the workflow again replaces the zip. Install it with Settings | Plugins | ⚙ | Install Plugin from Disk…;
such an install does not update itself, so once the plugin is on Marketplace, uninstall it and install from there.
Channels: a version with a suffix (0.2.0-beta, 0.2.0-beta.2) goes to the beta channel, a plain version
(1.0.0) to the default one. Beta users add the custom plugin repository
https://plugins.jetbrains.com/plugins/beta/list in Settings | Plugins | ⚙ | Manage Plugin Repositories.
These details come from JetBrains’ docs as of October 2026 or are assumptions; check them on the first release:
CERTIFICATE_CHAIN and PRIVATE_KEY: taken from the signing docs, not tried with real secrets.beta channel can be the hand-uploaded one, or the first upload must go to the
default channel. The docs say only that the first upload is manual.