Hey everyone! :wave: I've been building a Kotlin ...
# kotlin-toolchain
c
Hey everyone! ๐Ÿ‘‹ I've been building a Kotlin Toolchain plugin that integrates [OpenAPI Generator](https://openapi-generator.tech/) โ€” it lets you generate Kotlin/Java client/server code from an OpenAPI spec directly as part of your Kotlin Toolchain build, without needing Gradle. The plugin is at https://gitlab.com/curs3_w4ll/openapi-generator-kotlintoolchain-plugin. It already covers most of the generator's configuration surface (generator name, package names, type/import/schema mappings, etc.), and the generated sources are automatically picked up as a
kotlin
source set via the
generated.sources
plugin API. I'm now at the point where there are a handful of things I can't implement cleanly without a bit more from the Kotlin Toolchain side. I will list them as responses in the thread. Thanks for the great tooling!
1. Generated test source sets The OpenAPI Generator can emit test stubs alongside the main sources. Right now I have to suppress them globally (
apiTests=false
,
modelTests=false
) because the Kotlin Toolchain picks up the entire output directory as a single source set, and the test files fail to compile (no JUnit on the main classpath). Is there a way to declare a generated test source set from a plugin, or is that something on the roadmap? 2. Optional
@Input
paths
Some generator settings are optional file/directory paths โ€” for example
templateDir
(custom Mustache templates),
configFile
(external JSON config), or
ignoreFileOverride
. I'd like to mark these as
@Input
so the toolchain can track them for up-to-date checks, but nullable
Path?
annotated with
@Input
doesn't seem to be supported. What's the recommended way to handle optional path inputs in a task action? 3. Publishing I know plugin publishing support is on the way โ€” I'd love to be an early tester when it's ready! Is there anything I can do now to prepare, or a channel/issue to follow to stay in the loop?
โž• 1
f
Hi! Thanks for trying the feature out! We appreciate the feedback!
About optional inputs: nullable
@Input Path?
are supported. If something goes wrong, that's probably a bug then. Can you describe what happens if you try to use a nullable input path?
About generated test source sets. In fact that is possible using the
fragment
block, like this:
Copy code
generated:
  sources:
    - directory: ${<your-dir-ref>}
      fragment:
        isTest: true
You can try it out, see if this works for you.
m
Eagerly waiting on publishing as well, having people to clone a module isn't great
c
Awesome thanks! I will test this today and I will let you know here!
@Fedor Ihnatkevich For the test source sets I have trouble using the
generated.sources.fragment
in my plugin. Currently, the plugin is generating a bunch of files in the
${taskOutputDir}
:
build.gradle
,
src/main/kotlin/...
,
src/test/kotlin/...
. But I can't make specify a "sub directory" in
generated.sources.directory
. I tried doing
Copy code
generated:
  sources:
    - language: kotlin
      directory: ${tasks.generateOpenAPI.action.outputDir}/src/main/kotlin/
But this give me the following error from the kotlin-toolchain:
Copy code
The `directory` path `/Users/corentin/dev/openapi-generator-kotlintoolchain-plugin/build/tasks/_sub-package_generateOpenAPI@openapi-generator/src/main/kotlin` in must be an `@Output` of some task registered in this plugin
What am I supposed to do in this case? PS: Just so you know, I can't find any doc on the website about the
generated.sources.fragment
@Fedor Ihnatkevich And for the nullable
@Input
part Making the
Path
nullable in the
@TaskAction
@Input inputSpec: Path?,
implies that I also make it nullable on the settings class
Copy code
@Configurable
interface Settings {
  val inputSpec: String?
}
And this fails with the following:
Copy code
The value of type `string | null` cannot be used in string interpolation
f
For the test source sets
I have trouble using the
generated.sources.fragment
in my plugin.
Currently, the plugin is generating a bunch of files in the
${taskOutputDir}
:
build.gradle
,
src/main/kotlin/...
,
src/test/kotlin/...
.
But I can't make specify a "sub directory" in
generated.sources.directory
.
I see, thanks for reporting back! Yes, that is currently a UX limitation, that the
generated.sources.directory
must be exactly one of the
@Output
paths from the task, not a child path. The way to work around it now is to pass different
@Input
path parameters for generated directories, and then the
generated.sources
will allow referencing them. So basically instead of
Copy code
tasks:
  myTask:
    action: !someAction
      outputDir: ${taskOutputDir}
generated:
  sources:
    - directory: ${tasks.myTask.action.outputDir}/kotlin
  sources:
    - directory: ${tasks.myTask.action.outputDir}/java
      language: java
you will have
Copy code
tasks:
  myTask:
    action: !someAction
      kotlinOutputDir: ${taskOutputDir}/kotlin
      javaOutputDir: ${taskOutputDir}/java
generated:
  sources:
    - directory: ${tasks.myTask.action.kotlinOutputDir}
  sources:
    - directory: ${tasks.myTask.action.javaOutputDir}
      language: java
We are aware of this friction point, we might improve this aspect later!
โค๏ธ 1
๐Ÿ’ฏ 1
> And for the nullable
@Input
part > Making the
Path
nullable in the
@TaskAction
@Input inputSpec: Path?,
implies that I also make it nullable on the settings class >
Copy code
@Configurable
> interface Settings {
>   val inputSpec: String?
> }
> And this fails with the following: >
Copy code
The value of type `string | null` cannot be used in string interpolation
So the
@Input
path indeed can be nullable. What is not valid though, judging by the error message you get, is to use nullable string in a string/path interpolation. I'd very much like to see what exactly are you trying to do there, so I can understand what we can implement to enable use-cases like yours if there is no nice workaround possible. Can you share more snippets/code around this?
c
> Can you share more snippets/code around this? Sure, here is a branch where I have the issue: https://gitlab.com/curs3_w4ll/openapi-generator-kotlintoolchain-plugin/-/tree/18-support-configfile The issue is with the
configFile
setting, which is nullable in the
Settings
interface (as a
String
) and in the
openApiGenerate
@TaskAction
(as a
Path
)
๐Ÿ™ 2
Any news about this? ๐Ÿ‘€
f
I've looked at the project. When I try to reproduce the issue, (
configFile: String?
in the settings,
configFile: Path?
in the task,
configFile: ${pluginSettings.configFile}
in the
plugin.yaml
) then I get `The value of type
string | null
cannot be assigned to the type `path | null`` There is no string interpolation involved. If I append, say,
/
to the end (like this:
configFile: ${pluginSettings.configFile}/
) - then it becomes a string interpolation and I indeed see the error that you mentioned. So, nullable values can't be used in string-interpolation - it's the desired behavior for now. Unless we choose to introduce cascading-nullability into the type-system, or some tools like that. But it hasn't been designed yet and we need to consider cases and options there. Now, to the underlying problem that I see. According to our own simple "type-system" on top of YAML,
string
is not assignable to
path
, as it may contain invalid characters, wrong separators, etc. But this doesn't hold for string interpolations, so
myPath: ${myString}
is wrong, but
myPath: ${myString}/
is suddenly okay. So, currently, one indeed can use string interpolation to assign to a
path
property (not in the nullable case though, see above). This is a "gray zone" in the type-system and is inconsistent, so it has to be fixed. I've filed the issue about it - you can read more there - AMPER-5424 inconsistent:
string
is not assignable to
path
but string interpolation is.
โค๏ธ 1
Regarding your use-case, as I don't see any interpolation in the code, what prevents you from making your
configFile
a
Path
in the plugin settings? Then we avoid this whole shady string/path conversion story.
c
what prevents you from making your
configFile
a
Path
in the plugin settings?
Indeed I will ๐Ÿ˜„ I just didn't knew it was possible ๐Ÿ˜“ Because I followed the doc to write my settings file and in this doc, the
Path
parameter is set as a
String
in the settings class, so I did the same
f
Because I followed the doc to write my settings file
I see. We used
string
in the doc just for the file name, because you can't specify relative paths or path components (like just a file name) for now (AMPER-5403). But for paths that are expected to be specified fully by the client, you can use
path
no problem. Again, thanks for the feedback, I'll try to make the docs more clear about this!