Loading...
Loading...
Load when authoring, writing, or designing a Kotlin Toolchain local plugin to extend the declarative build with code generation, build-time processing, custom verification, or packaging that module.yaml cannot express, or when referencing @TaskAction, @Configurable, plugin.yaml, or jvm/amper-plugin. Skip for porting an existing Gradle plugin.
npx skill4agent add kotlin/kotlin-agent-skills kotlin-tooling-kotlin-toolchain-plugin-authoringjvm/amper-pluginproject.version./kotlin do releasemodule.yamlrepo-root/
├── kotlin, kotlin.bat # wrappers (from `kotlin init`)
├── project.yaml # registers the plugin
├── plugins/<name>/
│ ├── module.yaml # product: jvm/amper-plugin
│ ├── plugin.yaml # tasks: + commands: + generated:
│ └── src/
│ ├── Settings.kt # @Configurable interface
│ ├── tasks/ # one @TaskAction per file
│ │ ├── Foo.kt
│ │ └── FooSteps.kt # internal shared helpers (not @TaskAction)
│ └── <domain logic>/
└── <consumer-module>/
└── module.yaml # plugins: { <name>: enabled: true, ... }project.yamlmodules:
- consumer-app
- plugins/<name>
plugins:
- ./plugins/<name>plugins:module.yamlproduct: jvm/amper-plugin # marks the module as a plugin
dependencies:
- <coordinate>:<version>
- <coordinate>:<version>: runtime-only # required only at runtime
- <coordinate>:<version>: compile-only
pluginInfo:
id: <plugin-id> # what consumers write under `plugins:`
settingsClass: <fully.qualified.Settings> # the @Configurable interface
settings:
jvm:
jdk:
version: 21
kotlin:
languageVersion: 2.1@Configurable interface Settings@Configurable@Configurable
interface Settings {
val someValue: String get() = "default"
val checks: ChecksSettings
}
@Configurable
interface ChecksSettings {
val strict: Boolean get() = true
}module.yamlplugins:
<plugin-id>:
enabled: true
someValue: "override"
checks:
strict: false@TaskActionfunplugin.yaml@TaskAction
fun foo(
@Input moduleRootDir: Path,
@Output outputDir: Path,
settings: Settings,
) {
// body
}@Input path: Path@Output path: PathPathsettings: Settings@Configurableplugin.yamlPathplugin.yamlprintln(...)@TaskAction@TaskAction(executionAvoidance = ExecutionAvoidance.Disabled)
fun foo(@Output outputDir: Path, settings: Settings) { /* ... */ }@Outputplugin.yamltasks:
foo:
action: !<fully.qualified.foo>
moduleRootDir: ${module.rootDir}
outputDir: ${taskOutputDir}
settings: ${pluginSettings}
bar:
action: !<fully.qualified.bar>
input: ${tasks.foo.action.outputDir}/result.txt
settings: ${pluginSettings}
generated:
resources:
- directory: ${tasks.foo.action.outputDir}
commands:
- foo| Reference | Resolves to |
|---|---|
| Directory containing the consumer's |
| Toolchain-managed per-task output directory. Pass as |
| The |
| Another task's parameter — used in |
generated.resourcesgenerated.sources@Outputgenerated.resourcesgetResourceAsStream("/path/in/jar")generated.sourcessrc/./kotlin task :<module>:<task>@<plugin-id>./kotlin do <command-name>./kotlin show commands-m <module>@Outputgenerated.resourcesgenerated.sourcescommands:commands:project.version@Output outputDir: Pathplugin.yaml@Input${tasks.<producer>.action.outputDir}/<file>dependsOn@Output@Inputgenerated.resourcesgetResourceAsStream-Pkey=valueval forced = System.getenv("MYPLUGIN_FORCE_VALUE")?.takeIf { it.isNotBlank() }
val skipChecks = System.getenv("MYPLUGIN_SKIP_CHECKS")?.equals("true", ignoreCase = true) == trueSystem.getenv()plugins:${...}module.yamlProject.afterEvaluateProviderProperty-h--help./kotlin show commandsdemo-app/sample/main.kt