Gradle Plugin
The Gradle plugin contributes three tasks to any Gradle build: kumlRender, kumlGenerate,
and kumlValidate. All three are @CacheableTask with proper @InputDirectory /
@OutputDirectory annotations — incremental builds skip unchanged scripts.
|
The |
Apply the plugin
// build.gradle.kts
plugins {
id("dev.kuml") version "{kuml-version}"
}
That’s all you need to get the three tasks registered. Defaults are sensible:
-
Source directory:
src/main/kuml/ -
Output directory:
${buildDir}/kuml/ -
Format:
svg -
Theme:
kuml -
Generator:
kotlin
Override any of these in the kuml { … } extension block.
Configuration block
kuml {
sourceDir.set(file("src/main/kuml"))
outputDir.set(layout.buildDirectory.dir("kuml"))
format.set("svg") // "svg" | "png"
theme.set("elegant") // any ThemeRegistry name
widthPx.set(2048) // PNG width (ignored for SVG)
generator.set("java") // "kotlin" | "java" | "sql" | custom
generatePackage.set("com.example.domain") // Java/Kotlin package
generateOptions.put("java-style", "records")
generateOptions.put("sql-dialect", "postgres")
failOnValidationViolations.set(true) // fail the build on OCL violations
transformer.set("uml-to-exposed-via-erm") // kumlTransform: transformer id (no default)
transformOptions.put("idType", "uuid") // kumlTransform: transformer context options
transformModelName.set("merged") // name of the merged model
skipNonUmlScripts.set(false) // kumlTransform: skip C4/SysML scripts instead of failing
mergeScripts.set(false) // kumlGenerate: merge all scripts into one model first
}
Every property is a Gradle lazy Property / DirectoryProperty / MapProperty — you can
wire them to project conventions, settings, or other tasks.
kumlRender
./gradlew kumlRender
Walks sourceDir for *.kuml.kts files and renders each to outputDir, mirroring the
source’s directory structure:
src/main/kuml/
├── order.kuml.kts
└── billing/
└── invoice.kuml.kts
# →
build/kuml/
├── order.svg
└── billing/
└── invoice.svg
Inputs (cacheable):
-
sourceDir(PathSensitive=RELATIVE) -
format,theme,widthPx
Outputs:
-
outputDir
A second ./gradlew kumlRender with no source changes is UP-TO-DATE.
kumlGenerate
./gradlew kumlGenerate
Runs the configured generator over every diagram in sourceDir. C4 scripts are skipped
automatically (only UML diagrams produce code). Output goes to outputDir/generated/
by default.
Wire into other tasks:
tasks.named<JavaCompile>("compileJava") {
dependsOn("kumlGenerate")
source(layout.buildDirectory.dir("kuml/generated"))
}
For Kotlin source, point srcDirs of the main source set at the same directory.
By default the generator runs once per script. With mergeScripts.set(true) all UML class scripts are merged into
one model first (see kumlTransform for the merge rules) and the generator runs once on it.
Scripts that are not UML class diagrams are skipped.
kumlTransform
./gradlew kumlTransform
Merges all *.kuml.kts UML class scripts below sourceDir into one model and applies the configured
transformer once. Stub entities that scripts declare only to reference a foreign entity are removed. The merge
rules are the same as for kuml transform with several scripts; a conflict
fails the build with a message that names the table, both classes, both scripts and the attributes.
kuml {
sourceDir.set(file("src/main/kuml"))
transformer.set("uml-to-exposed-via-erm")
transformOptions.putAll(mapOf("idType" to "uuid", "package" to "com.example.db.generated"))
}
// Wires the output as a source directory and adds the task dependency.
kotlin.sourceSets.named("main") { kotlin.srcDir(tasks.named("kumlTransform")) }
-
Output goes to
outputDir/transform/by default. The directory is cleaned before every run, so outputs of removed scripts disappear.outputDirmust not be, lie inside, or containsourceDir. -
Scripts are processed in sorted order of their path relative to
sourceDir; the result is deterministic. -
The task is cacheable and compatible with the configuration cache.
-
Limits: at most 1000 scripts and 1 MiB per script by default (
maxScripts,maxScriptByteson the task). Symbolic links that lead out ofsourceDirfail the build. -
A script that is not a UML class diagram (for example C4) fails the build and names the file. Set
skipNonUmlScripts.set(true)to skip such scripts instead. -
The Exposed transformers (
uml-to-exposed-via-erm,uml-to-exposed) ship with the plugin. Compiling the generated Exposed code needs the Exposed libraries on your own compile classpath.
kumlValidate
./gradlew kumlValidate
Runs OclValidator over every *.kuml.kts in sourceDir. Hangs on to the build’s
check lifecycle:
plugins {
id("dev.kuml")
java
}
// check automatically depends on kumlValidate
If failOnValidationViolations = true (default), violations fail the build with a
human-readable error listing each violation. If false, the same information is logged as
a warning but the build continues — useful for grace-period rollouts.
Multi-project builds
In a multi-project build, apply the plugin only to the projects that own kUML scripts:
// settings.gradle.kts
include(":app", ":domain", ":docs")
// docs/build.gradle.kts
plugins {
id("dev.kuml")
}
kuml {
sourceDir.set(file("src/main/kuml"))
outputDir.set(layout.buildDirectory.dir("kuml"))
}
The plugin is self-contained — no parent project configuration needed.
Reproducibility
The Gradle plugin uses the same scripting host, layout engines, themes, and generators as the CLI. Outputs are byte-identical:
diff <(kuml render src/main/kuml/order.kuml.kts) build/kuml/order.svg
# (no output — files are identical)
That makes CI cache invalidation straightforward: a commit that changes a *.kuml.kts
invalidates the corresponding output; everything else stays cached.
Building the plugin from source
The published plugin (see above) is the recommended path for consumers. If you need an unreleased fix or are developing the plugin itself, publish a local copy instead:
./gradlew :kuml-gradle:kuml-gradle-plugin:publishToMavenLocal
Then in your consumer build’s settings.gradle.kts:
pluginManagement {
repositories {
mavenLocal()
gradlePluginPortal()
}
}
Apply as usual: id("dev.kuml") version "X.Y.Z-SNAPSHOT".