Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 45 additions & 5 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@
# fails publishes nothing, and its deployments can be dropped in the Portal.
#
# Once Maven Central serves both, the Gradle plugins go to the Gradle Plugin Portal, signed with the same
# release key. After publishing, a draft GitHub release on the tag collects the runnable jar, the Gradle
# release key, and the IntelliJ plugin goes to the JetBrains Marketplace, verified against the IDEs it
# supports first. After publishing, a draft GitHub release on the tag collects the runnable jar, the Gradle
# and IDE plugins and the native binaries.
#
# Needs six repository secrets: JRELEASER_MAVENCENTRAL_USERNAME and JRELEASER_MAVENCENTRAL_PASSWORD (the
# Central Portal user token), JRELEASER_GPG_SECRET_KEY and JRELEASER_GPG_PASSPHRASE, and
# GRADLE_PUBLISH_KEY and GRADLE_PUBLISH_SECRET (the Gradle Plugin Portal key). The draft release uses the
# workflow's own GITHUB_TOKEN.
# Needs seven repository secrets: JRELEASER_MAVENCENTRAL_USERNAME and JRELEASER_MAVENCENTRAL_PASSWORD (the
# Central Portal user token), JRELEASER_GPG_SECRET_KEY and JRELEASER_GPG_PASSPHRASE, GRADLE_PUBLISH_KEY and
# GRADLE_PUBLISH_SECRET (the Gradle Plugin Portal key) and JETBRAINS_MARKETPLACE_TOKEN (a permanent token of
# the Marketplace account that owns the plugin). The draft release uses the workflow's own GITHUB_TOKEN.
on:
push:
tags:
Expand Down Expand Up @@ -270,6 +271,45 @@
JRELEASER_GPG_SECRET_KEY: ${{ secrets.JRELEASER_GPG_SECRET_KEY }}
JRELEASER_GPG_PASSPHRASE: ${{ secrets.JRELEASER_GPG_PASSPHRASE }}

# The IntelliJ plugin carries the formatter jars inside its zip, so it does not wait for Maven Central. It
# waits for the publish job like everything else, so that a version whose jars or native images failed
# stays off the Marketplace too. The plugin is checked against the IDEs it declares support for before it
# goes up; a plugin that fails there would fail JetBrains' own check after the upload anyway. The
# Marketplace never takes a version back and rejects a version it already has, so a re-run of this job
# fails once the upload went through.
jetbrains-plugin:
name: JetBrains Marketplace
needs: publish
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0
Comment on lines +286 to +288

- name: Install JDK 21
uses: actions/setup-java@de7274f081f381c8f8158605e0321c36c376e2e6 # v6.0.1
with:
distribution: temurin
java-version: '21'

- name: Verify the plugin against the IDEs it supports
run: ./gradlew :open-java-format-idea-plugin:verifyPlugin

- name: Keep the verifier's report
if: ${{ failure() }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: plugin-verifier-report
path: open-java-format-idea-plugin/build/reports/pluginVerifier
if-no-files-found: ignore
retention-days: 7

- name: Upload the plugin
run: ./gradlew :open-java-format-idea-plugin:publishPlugin
env:
JETBRAINS_MARKETPLACE_TOKEN: ${{ secrets.JETBRAINS_MARKETPLACE_TOKEN }}

# What Maven Central does not carry — the runnable formatter jar, the Gradle plugins' jar, the IntelliJ
# plugin zip, the Eclipse plugin jar, and every platform's native binary as a plain download — goes into
# a draft GitHub release on the tag, each file signed with the release key. Only once both deployments
Expand Down
1 change: 1 addition & 0 deletions mise.toml
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,5 @@ apply JRELEASER_GPG_SECRET_KEY 'op://Private/open-java-format/GitHub/JRELEASER_G
apply JRELEASER_GPG_PASSPHRASE 'op://Private/open-java-format/GitHub/JRELEASER_GPG_PASSPHRASE' actions
apply GRADLE_PUBLISH_KEY 'op://Private/open-java-format/GitHub/GRADLE_PUBLISH_KEY' actions
apply GRADLE_PUBLISH_SECRET 'op://Private/open-java-format/GitHub/GRADLE_PUBLISH_SECRET' actions
apply JETBRAINS_MARKETPLACE_TOKEN 'op://Private/open-java-format/GitHub/JETBRAINS_MARKETPLACE_TOKEN' actions
"""
33 changes: 32 additions & 1 deletion open-java-format-idea-plugin/build.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType
import org.jetbrains.intellij.platform.gradle.TestFrameworkType
import org.jetbrains.intellij.platform.gradle.models.ProductRelease
import org.jetbrains.intellij.platform.gradle.tasks.VerifyPluginTask

/*
* Copyright 2017 Google Inc. All Rights Reserved.
Expand Down Expand Up @@ -100,10 +103,38 @@ intellijPlatform {
}
}

// publishPlugin uploads the zip to the JetBrains Marketplace, from the release workflow (see
// .github/workflows/release.yml). The token is a permanent token of the Marketplace account that owns
// the plugin; without it the task fails before uploading anything. The Marketplace never takes a version
// back and rejects a version it already has. The zip goes up unsigned, and the Marketplace signs it with
// the JetBrains key; a signature of our own would take a `signing { }` block here and three more secrets.
publishing {
// Inert until the token is present; wiring the marketplace release is Phase 2 work.
token = providers.environmentVariable('JETBRAINS_MARKETPLACE_TOKEN')
}

// verifyPlugin checks the plugin's bytecode against real IDEs, which it downloads. Two of them: the
// IDE the plugin is built against, which is the oldest one sinceBuild admits, and the newest IntelliJ
// IDEA release. The default, recommended(), would take every major version in between, which is a
// gigabyte per IDE for nothing the two ends do not show, and it stops at 2025.2: since 2025.3 IntelliJ
// IDEA is one product (IntellijIdea), no longer split into Community and Ultimate.
pluginVerification {
// Fail on what would break an installation: classes or methods the IDE no longer has, a dependency
// it lacks, an invalid descriptor. Usages of internal, deprecated or experimental API stay warnings
// in the report: 2026.2 marked every way of looking a plugin descriptor up as @ApiStatus.Internal,
// PluginManager.findEnabledPlugin included, and a warning about that must not hold a release.
failureLevel = [
VerifyPluginTask.FailureLevel.COMPATIBILITY_PROBLEMS,
VerifyPluginTask.FailureLevel.MISSING_DEPENDENCIES,
VerifyPluginTask.FailureLevel.INVALID_PLUGIN,
]
ides {
current()
latest {
it.types.set([IntelliJPlatformType.IntellijIdea])
it.channels.set([ProductRelease.Channel.RELEASE])
}
}
}
}

// This task resolves runtimeClasspath without telling Gradle it depends on it, so the dependent
Expand Down
Loading