Files
zeekay a3907e3063 Sign in to the JetBrains plugin through IAM
IAM owns sign-in, so the plugin no longer collects a password or an API
key. Login opens hanzo.id in the browser and takes the redirect on a
one-shot listener at 127.0.0.1 (RFC 8252, client hanzo-jetbrains); the
code exchange (PKCE), refresh, revoke and userinfo go to
api.hanzo.ai/v1/iam. Tokens refresh before they lapse, and logout
revokes the refresh token. Chat and models use api.hanzo.ai, the one
API host.

The build script compiles on JDK 21, where List.first resolves to
getFirst and the Kotlin DSL then invokes the string as a task name, so
the publish channel now comes from substringBefore. gradle-intellij-
plugin 1.17.4 keeps its coroutines agent across clean, okhttp stops
bundling a second Kotlin stdlib, and the tests are JUnit 5, the engine
the build runs.

Claude-Session: https://claude.ai/code/session_01Dc8DXc3fEQCRHUa6XWK4Ku
2026-09-29 12:10:37 -07:00

124 lines
4.1 KiB
Kotlin

import org.jetbrains.changelog.Changelog
import org.jetbrains.changelog.markdownToHTML
import org.jetbrains.intellij.tasks.RunPluginVerifierTask
fun properties(key: String) = providers.gradleProperty(key)
fun environment(key: String) = providers.environmentVariable(key)
plugins {
id("java")
id("org.jetbrains.kotlin.jvm") version "1.9.21"
id("org.jetbrains.intellij") version "1.17.4"
id("org.jetbrains.changelog") version "2.2.0"
}
group = properties("pluginGroup").get()
version = properties("pluginVersion").get()
repositories {
mavenCentral()
}
dependencies {
// The IDE provides the Kotlin stdlib; a bundled second copy splits class
// identity between the plugin and the platform.
implementation("com.squareup.okhttp3:okhttp:4.12.0") {
exclude(group = "org.jetbrains.kotlin")
}
implementation("com.google.code.gson:gson:2.10.1")
testImplementation("org.junit.jupiter:junit-jupiter:5.10.1")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
testImplementation("org.mockito:mockito-core:5.8.0")
testImplementation(kotlin("test"))
}
kotlin {
jvmToolchain(17)
}
intellij {
pluginName = properties("pluginName")
version = properties("platformVersion")
type = properties("platformType")
plugins = properties("platformPlugins").map { it.split(',').map(String::trim).filter(String::isNotEmpty) }
}
changelog {
groups.empty()
repositoryUrl = properties("pluginRepositoryUrl")
}
tasks {
wrapper {
gradleVersion = properties("gradleVersion").get()
}
// buildSearchableOptions launches a headless IDE (JCEF) to pre-index plugin
// settings — it needs native font libs (libfreetype) the CI runners lack, so
// it crashes buildPlugin non-deterministically (only passing when the task is
// cache-UP-TO-DATE). The index is optional; the IDE rebuilds it at runtime.
// Disable it so buildPlugin reliably produces the distributable zip.
buildSearchableOptions {
enabled = false
}
patchPluginXml {
version = properties("pluginVersion")
sinceBuild = properties("pluginSinceBuild")
untilBuild = properties("pluginUntilBuild")
pluginDescription = providers.fileContents(layout.projectDirectory.file("README.md")).asText.map {
val start = "<!-- Plugin description -->"
val end = "<!-- Plugin description end -->"
with (it.lines()) {
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").let(::markdownToHTML)
}
}
val changelog = project.changelog
changeNotes = properties("pluginVersion").map { pluginVersion ->
with(changelog) {
renderItem(
(getOrNull(pluginVersion) ?: getUnreleased())
.withHeader(false)
.withEmptySections(false),
Changelog.OutputType.HTML,
)
}
}
}
runIdeForUiTests {
systemProperty("robot-server.port", "8082")
systemProperty("ide.mac.message.dialogs.as.sheets", "false")
systemProperty("jb.privacy.policy.text", "<!--999.999-->")
systemProperty("jb.consents.confirmation.enabled", "false")
}
signPlugin {
certificateChain = environment("CERTIFICATE_CHAIN")
privateKey = environment("PRIVATE_KEY")
password = environment("PRIVATE_KEY_PASSWORD")
}
publishPlugin {
dependsOn("patchChangelog")
token = environment("PUBLISH_TOKEN")
channels = properties("pluginVersion").map { listOf(it.split('-').getOrElse(1) { "default" }.substringBefore('.')) }
}
runPluginVerifier {
ideVersions = properties("pluginVerifierIdeVersions").map { it.split(',').map(String::trim).filter(String::isNotEmpty) }
failureLevel = RunPluginVerifierTask.FailureLevel.ALL
}
test {
useJUnitPlatform()
}
}