├── .github ├── labeler.yml └── workflows │ ├── community.yml │ └── sbt.yml ├── .gitignore ├── .java-version ├── LICENSE ├── README.md ├── build.sbt ├── project ├── build.properties └── plugin.sbt ├── publish.sbt └── src ├── main └── scala │ └── org │ └── openapitools │ └── generator │ └── sbt │ └── plugin │ ├── OpenApiGeneratorKeys.scala │ ├── OpenApiGeneratorPlugin.scala │ └── tasks │ ├── OpenApiGenerateTask.scala │ └── OpenApiGeneratorsTask.scala └── sbt-test └── sbt-openapi-generator └── simple ├── build.sbt ├── config.yaml ├── openapi.yaml ├── project ├── build.properties └── plugin.sbt ├── src └── main │ └── scala │ └── Main.scala ├── test └── version.sbt /.github/labeler.yml: -------------------------------------------------------------------------------- 1 | # labeler "full" schema 2 | # see https://github.com/marketplace/actions/auto-labeler 3 | # enable labeler on issues, prs, or both. 4 | enable: 5 | issues: true 6 | prs: true 7 | 8 | # comments object allows you to specify a different message for issues and prs 9 | comments: 10 | issues: | 11 | Thanks for opening this issue! 12 | We've automatically applied any labels matching text in your issue. 13 | prs: | 14 | Thanks for the contribution! 15 | We've automatically applied labels that seem to represent your pull request. 16 | 17 | # Labels is an object where: 18 | # - keys are labels 19 | # - values are objects of { include: [ pattern ], exclude: [ pattern ] } 20 | # - pattern must be a valid regex, and is applied globally to 21 | # title + description of issues and/or prs (see enabled config above) 22 | # - 'include' patterns will associate a label if any of these patterns match 23 | # - 'exclude' patterns will ignore this label if any of these patterns match 24 | labels: 25 | 'bug': 26 | include: 27 | - '\s*?\[bug(s)?\]\b' 28 | - '\s*?\[fix\]\b' 29 | exclude: [] 30 | 'help wanted': 31 | include: 32 | - '\bhelp wanted\b' 33 | exclude: 34 | - '\bquestion\b' 35 | - '\bhelp( me)?\b' 36 | 'question': 37 | include: 38 | - '\bhelp( me)?\b' 39 | - '\b\[question\]\b' 40 | 'enhancement': 41 | include: 42 | - '\bfeat\b' 43 | - '\bfeature\b' 44 | exclude: [] -------------------------------------------------------------------------------- /.github/workflows/community.yml: -------------------------------------------------------------------------------- 1 | name: Community 2 | on: 3 | issues: 4 | types: [opened, edited, milestoned] 5 | pull_request_target: 6 | types: [opened] 7 | 8 | jobs: 9 | 10 | labeler: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - name: Check Labels 15 | id: labeler 16 | uses: jimschubert/labeler-action@v1 17 | with: 18 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 19 | -------------------------------------------------------------------------------- /.github/workflows/sbt.yml: -------------------------------------------------------------------------------- 1 | name: Scala CI 2 | 3 | # Support "official releases" on master, and release fixes on release/ prefixed branches 4 | on: 5 | push: 6 | branches: 7 | - 'master' 8 | - 'releases/**' 9 | - '!releases/**-alpha' 10 | paths-ignore: 11 | - 'docs/**' 12 | - 'README.md' 13 | pull_request: 14 | branches: 15 | - 'master' 16 | # trigger on new branch/tag creation 17 | create: [] 18 | 19 | jobs: 20 | build: 21 | runs-on: ubuntu-latest 22 | steps: 23 | - uses: actions/checkout@v2 24 | with: 25 | fetch-depth: 0 26 | - name: Set up JDK 27 | uses: actions/setup-java@v2 28 | with: 29 | java-version: 11 30 | distribution: temurin 31 | - name: Setup sbt launcher 32 | uses: sbt/setup-sbt@v1 33 | - name: Cache SBT ivy cache 34 | uses: actions/cache@v4 35 | with: 36 | path: ~/.ivy2/cache 37 | key: ${{ runner.os }}-sbt-ivy-cache-${{ hashFiles('**/*.sbt') }} 38 | - name: Cache SBT 39 | uses: actions/cache@v4 40 | with: 41 | path: ~/.sbt 42 | key: ${{ runner.os }}-sbt-${{ hashFiles('**/*.sbt') }} 43 | - name: Run tests 44 | run: sbt ^test ^scripted 45 | #- name: Publish 46 | # if: github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v') 47 | # env: 48 | # BINTRAY_USER: ${{ secrets.BINTRAY_USER }} 49 | # BINTRAY_PASS: ${{ secrets.BINTRAY_PASS }} 50 | # run: sbt ^publish 51 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .bsp 2 | 3 | # Created by https://www.gitignore.io/api/osx,sbt,linux,scala,intellij 4 | # Edit at https://www.gitignore.io/?templates=osx,sbt,linux,scala,intellij 5 | 6 | ### Intellij ### 7 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 8 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 9 | 10 | # User-specific stuff 11 | .idea/**/workspace.xml 12 | .idea/**/tasks.xml 13 | .idea/**/usage.statistics.xml 14 | .idea/**/dictionaries 15 | .idea/**/shelf 16 | 17 | # Generated files 18 | .idea/**/contentModel.xml 19 | 20 | # Sensitive or high-churn files 21 | .idea/**/dataSources/ 22 | .idea/**/dataSources.ids 23 | .idea/**/dataSources.local.xml 24 | .idea/**/sqlDataSources.xml 25 | .idea/**/dynamic.xml 26 | .idea/**/uiDesigner.xml 27 | .idea/**/dbnavigator.xml 28 | 29 | # Gradle 30 | .idea/**/gradle.xml 31 | .idea/**/libraries 32 | 33 | # Gradle and Maven with auto-import 34 | # When using Gradle or Maven with auto-import, you should exclude module files, 35 | # since they will be recreated, and may cause churn. Uncomment if using 36 | # auto-import. 37 | # .idea/modules.xml 38 | # .idea/*.iml 39 | # .idea/modules 40 | *.iml 41 | *.ipr 42 | 43 | # CMake 44 | cmake-build-*/ 45 | 46 | # Mongo Explorer plugin 47 | .idea/**/mongoSettings.xml 48 | 49 | # File-based project format 50 | *.iws 51 | 52 | # IntelliJ 53 | out/ 54 | 55 | # mpeltonen/sbt-idea plugin 56 | .idea_modules/ 57 | 58 | # JIRA plugin 59 | atlassian-ide-plugin.xml 60 | 61 | # Cursive Clojure plugin 62 | .idea/replstate.xml 63 | 64 | # Crashlytics plugin (for Android Studio and IntelliJ) 65 | com_crashlytics_export_strings.xml 66 | crashlytics.properties 67 | crashlytics-build.properties 68 | fabric.properties 69 | 70 | # Editor-based Rest Client 71 | .idea/httpRequests 72 | 73 | # Android studio 3.1+ serialized cache file 74 | .idea/caches/build_file_checksums.ser 75 | 76 | ### Intellij Patch ### 77 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 78 | 79 | # *.iml 80 | # modules.xml 81 | # .idea/misc.xml 82 | # *.ipr 83 | 84 | # Sonarlint plugin 85 | .idea/**/sonarlint/ 86 | 87 | # SonarQube Plugin 88 | .idea/**/sonarIssues.xml 89 | 90 | # Markdown Navigator plugin 91 | .idea/**/markdown-navigator.xml 92 | .idea/**/markdown-navigator/ 93 | 94 | ### Linux ### 95 | *~ 96 | 97 | # temporary files which can be created if a process still has a handle open of a deleted file 98 | .fuse_hidden* 99 | 100 | # KDE directory preferences 101 | .directory 102 | 103 | # Linux trash folder which might appear on any partition or disk 104 | .Trash-* 105 | 106 | # .nfs files are created when an open file is removed but is still being accessed 107 | .nfs* 108 | 109 | ### OSX ### 110 | # General 111 | .DS_Store 112 | .AppleDouble 113 | .LSOverride 114 | 115 | # Icon must end with two \r 116 | Icon 117 | 118 | # Thumbnails 119 | ._* 120 | 121 | # Files that might appear in the root of a volume 122 | .DocumentRevisions-V100 123 | .fseventsd 124 | .Spotlight-V100 125 | .TemporaryItems 126 | .Trashes 127 | .VolumeIcon.icns 128 | .com.apple.timemachine.donotpresent 129 | 130 | # Directories potentially created on remote AFP share 131 | .AppleDB 132 | .AppleDesktop 133 | Network Trash Folder 134 | Temporary Items 135 | .apdisk 136 | 137 | ### SBT ### 138 | # Simple Build Tool 139 | # http://www.scala-sbt.org/release/docs/Getting-Started/Directories.html#configuring-version-control 140 | 141 | dist/* 142 | target/ 143 | lib_managed/ 144 | src_managed/ 145 | project/boot/ 146 | project/plugins/project/ 147 | .history 148 | .cache 149 | .lib/ 150 | 151 | ### Scala ### 152 | *.class 153 | *.log 154 | *.metals 155 | 156 | # End of https://www.gitignore.io/api/osx,sbt,linux,scala,intellij 157 | 158 | .vscode 159 | metals.sbt 160 | .bloop -------------------------------------------------------------------------------- /.java-version: -------------------------------------------------------------------------------- 1 | 11 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 OpenAPI-Generator Contributors (https://openapi-generator.tech) 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sbt-openapi-generator 2 | 3 | ![Scala CI](https://github.com/openAPITools/sbt-openapi-generator/workflows/Scala%20CI/badge.svg?branch=master) 4 | 5 | A Sbt plugin to support the OpenAPI generator project. 6 | 7 | # Usage 8 | 9 | Add to your `project/plugins.sbt`: 10 | 11 | ```sbt 12 | addSbtPlugin("org.openapitools" % "sbt-openapi-generator" % "7.13.0") 13 | ``` 14 | 15 | # Configuration 16 | 17 | Configuration based on project module is recommended way to separate specifications by modules. 18 | 19 | You must define one of the settings `openApiInputSpec` or `openApiConfigFile` to able run plugin to generate. 20 | 21 | Settings will be picked up from `openApiConfigFile` first if defined and then will be overwritten with module specified 22 | settings if provided 23 | 24 | With the next example module `generated` will be defined as: 25 | 26 | ```sbt 27 | lazy val generated = project.in(file("generated")) 28 | .settings( 29 | openApiInputSpec := "openapi.yaml", 30 | openApiConfigFile := "config.yaml" 31 | ) 32 | ``` 33 | 34 | There is a helpers to have boolean settings more readable. Instead of `Some(true)` it possible to do next: 35 | ```sbt 36 | openApiValidateSpec := SettingDisabled, 37 | openApiGenerateModelTests := SettingEnabled, 38 | ``` 39 | # Execution 40 | 41 | To print all available languages use 42 | ```shell script 43 | sbt openApiGenerators 44 | ``` 45 | 46 | To run template generation process 47 | ```shell script 48 | sbt openApiGenerate 49 | ``` 50 | or per defined module 51 | ```shell script 52 | sbt generated/openApiGenerate 53 | ``` 54 | 55 | # Settings 56 | 57 | 58 | | Setting | Type | Description | 59 | |----------|--------|--------------------------| 60 | | openApiGeneratorName *| `String` | The name of the generator which will handle codegen. (see \"openApiGenerators\" task)
Required. Can be provided as `generatorName` option of `openApiConfigFile` json config | 61 | | openApiInputSpec *| `String` | The Open API 2.0/3.x specification location (file or url)
Required. Can be provided as `inputSpec` option of `openApiConfigFile` json config | 62 | | openApiOutputDir| `String` | The output target directory into which code will be generated | 63 | | openApiConfigFile **| `String` | Path to json configuration file
This setting is required with `generatorName` and `inputSpec` settings provided if sbt settings `openApiGeneratorName` and `openApiInputSpec` are absent | 64 | | openApiAdditionalProperties | `Map[String, String]` | Sets additional properties that can be referenced by the mustache templates in the format of name=value,name=value. You can also have multiple occurrences of this option | 65 | | openApiGlobalProperties | `Map[String, String]` |Sets specified system properties | 66 | | openApiVerbose | `Option[Boolean]` | The verbosity of generation | 67 | | openApiValidateSpec | `Option[Boolean]` | Whether or not an input specification should be validated upon generation | 68 | | openApiTemplateDir | `String` | The template directory holding a custom template | 69 | | openApiAuth | `String` | Adds authorization headers when fetching the OpenAPI definitions remotely. Pass in a URL-encoded string of name:header with a comma separating multiple values | 70 | | openApiSkipOverwrite | `Option[Boolean]` | Specifies if the existing files should be overwritten during the generation | 71 | | openApiPackageName | `String` | Package for generated classes (where supported) | 72 | | openApiApiPackage | `String` | Package for generated api classes | 73 | | openApiModelPackage | `String` | Package for generated models | 74 | | openApiModelNamePrefix | `String` | Prefix that will be prepended to all model names | 75 | | openApiModelNameSuffix | `String` | Suffix that will be appended to all model names | 76 | | openApiInstantiationTypes | `Map[String, String]` | Sets instantiation type mappings | 77 | | openApiTypeMappings | `Map[String, String]` | Sets mappings between OpenAPI spec types and generated code types | 78 | | openApiServerVariables | `Map[String, String]` | Sets server variable for server URL template substitution, in the format of name=value,name=value. You can also have multiple occurrences of this option | 79 | | openApiLanguageSpecificPrimitives | `List[String]` | Specifies additional language specific primitive types in the format of type1,type2,type3,type3. For example: String,boolean,Boolean,Double | 80 | | openApiImportMappings | `Map[String, String]` | Specifies mappings between a given class and the import that should be used for that class | 81 | | openApiInvokerPackage | `String` | Root package for generated code | 82 | | openApiGroupId | `String` | groupId in generated pom.xml/build.sbt | 83 | | openApiId | `String` | artifactId in generated pom.xml/build.sbt. This also becomes part of the generated library's filename | 84 | | openApiLibrary | `String` | library template (sub-template) | 85 | | openApiGitHost | `String` |Git host, e.g. gitlab.com | 86 | | openApiGitUserId | `String` | Git user ID, e.g. openapitools | 87 | | openApiGitRepoId | `String` | Git repo ID, e.g. openapi-generator | 88 | | openApiReleaseNote | `String` | Release note, default to 'Minor update' | 89 | | openApiHttpUserAgent | `String` | HTTP user agent, e.g. codegen_csharp_api_client, default to 'OpenAPI-Generator/{packageVersion}}/{language}' | 90 | | openApiReservedWordsMappings | `Map[String, String]` | ]("Specifies how a reserved name should be escaped to | 91 | | openApiIgnoreFileOverride | `String` | Specifies an override location for the .openapi-generator-ignore file. Most useful on initial generation. | 92 | | openApiRemoveOperationIdPrefix | `Option[Boolean]` | Remove prefix of operationId, e.g. config_getId => getId | 93 | | openApiApiFilesConstrainedTo | `List[String]` | Defines which API-related files should be generated. This allows you to create a subset of generated files (or none at all) | 94 | | openApiModelFilesConstrainedTo | `List[String]` | Defines which model-related files should be generated. This allows you to create a subset of generated files (or none at all) | 95 | | openApiSupportingFilesConstrainedTo | `List[String]` | Defines which supporting files should be generated. This allows you to create a subset of generated files (or none at all | 96 | | openApiGenerateModelTests | `Option[Boolean]` | Specifies that model tests are to be generated | 97 | | openApiGenerateModelDocumentation | `Option[Boolean]` | Defines whether or not model-related _documentation_ files should be generated | 98 | | openApiGenerateApiTests | `Option[Boolean]` | Specifies that api tests are to be generated | 99 | | openApiGenerateApiDocumentation | `Option[Boolean]` | Defines whether or not api-related _documentation_ files should be generated | 100 | | openApiWithXml | `Option[Boolean]` | A special-case setting which configures some generators with XML support. In some cases, this forces json OR xml, so the default here is false | 101 | | openApiLogToStderr | `Option[Boolean]` | To write all log messages (not just errors) to STDOUT | 102 | | openApiEnablePostProcessFile | `Option[Boolean]` | Enable post-processing file using environment variables | \ 103 | | openApiSkipValidateSpec | `Option[Boolean]` | To skip spec validation. When true, we will skip the default behavior of validating a spec before generation | 104 | | openApiGenerateAliasAsModel | `Option[Boolean]` | Generate model implementation for aliases to map and array schemas | 105 | | openApiGenerateMetadata | `Option[Boolean]` | Generate metadata files used by OpenAPI Generator. This includes `.openapi-generator-ignore` and any files within `.openapi-generator`. | 106 | 107 | # Examples 108 | 109 | Please see [an sbt-test configuration](src/sbt-test) for examples of using the plugin. 110 | Do not run those examples directly, please copy them to separate place first. 111 | 112 | # Contribution and Tests 113 | 114 | Write plugin integration tests under [src/sbt-test](src/sbt-test) 115 | 116 | Execute next command to run tests: 117 | 118 | ```shell script 119 | sbt scripted 120 | ``` 121 | 122 | More information about how to write and execute tests [is here](https://www.scala-sbt.org/1.x/docs/Testing-sbt-plugins.html) 123 | -------------------------------------------------------------------------------- /build.sbt: -------------------------------------------------------------------------------- 1 | ThisBuild / name := "sbt-openapi-generator" 2 | ThisBuild / description := 3 | """ 4 | This plugin supports common functionality found in Open API Generator CLI as a sbt plugin. 5 | 6 | This gives you the ability to generate client SDKs, documentation, new generators, and to validate Open API 2.0 and 3.x 7 | specifications as part of your build. Other tasks are available as command line tasks. 8 | """ 9 | 10 | lazy val `sbt-openapi-generator` = (project in file(".")) 11 | .settings( 12 | scalaVersion := "2.12.15", 13 | crossScalaVersions := Seq(scalaVersion.value, "2.11.12"), 14 | crossSbtVersions := List("0.13.17", "1.3.10"), 15 | sbtPlugin := true, 16 | 17 | publishMavenStyle := true, 18 | 19 | scriptedLaunchOpts := { 20 | scriptedLaunchOpts.value ++ Seq("-Xmx1024M", "-server", "-Dplugin.version=" + version.value) 21 | }, 22 | 23 | scriptedBufferLog := false, 24 | 25 | resolvers ++= Seq( 26 | Resolver.sbtPluginRepo("snapshots"), 27 | Resolver.sonatypeRepo("snapshots") 28 | ), 29 | 30 | version := "7.13.0", 31 | 32 | homepage := Some(url("https://openapi-generator.tech")), 33 | 34 | organization := "org.openapitools", 35 | organizationName := "OpenAPI-Generator Contributors", 36 | organizationHomepage := Some(url("https://github.com/OpenAPITools")), 37 | 38 | licenses += ("The Apache Software License, Version 2.0", url("https://www.apache.org/licenses/LICENSE-2.0.txt")), 39 | 40 | developers += Developer( 41 | id = "openapitools", 42 | name = "OpenAPI-Generator Contributors", 43 | email = "team@openapitools.org", 44 | url = url("https://github.com/OpenAPITools") 45 | ), 46 | 47 | scmInfo := Some( 48 | ScmInfo( 49 | browseUrl = url("https://github.com/OpenAPITools/openapi-generator"), 50 | connection = "scm:git:git://github.com/OpenAPITools/openapi-generator.git", 51 | devConnection = "scm:git:ssh://git@github.com:OpenAPITools/openapi-generator.git") 52 | ), 53 | 54 | libraryDependencies += "org.openapitools" % "openapi-generator" % "7.13.0" 55 | ).enablePlugins(SbtPlugin) 56 | -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.6.2 2 | -------------------------------------------------------------------------------- /project/plugin.sbt: -------------------------------------------------------------------------------- 1 | // Manages publishing. 2 | //addSbtPlugin("org.foundweekends" % "sbt-bintray" % "0.5.6") 3 | addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "3.10.0") 4 | 5 | // Versions the build. 6 | //addSbtPlugin("com.dwijnand" % "sbt-dynver" % "5.0.1") 7 | -------------------------------------------------------------------------------- /publish.sbt: -------------------------------------------------------------------------------- 1 | ThisBuild / organization := "org.openapitools.sbt-openapi-generator" 2 | ThisBuild / organizationName := "OpenAPITools" 3 | ThisBuild / organizationHomepage := Some(url("http://openapitools.org")) 4 | 5 | ThisBuild / scmInfo := Some( 6 | ScmInfo( 7 | url("https://github.com/openapitools/sbt-openapi-generator"), 8 | "scm:git@github.com:openapitools/sbt-openapi-generator.git" 9 | ) 10 | ) 11 | ThisBuild / developers := List( 12 | Developer( 13 | id = "openapitools", 14 | name = "OpenAPI Tools", 15 | email = "team@openapitools.org", 16 | url = url("http://openapitools.org") 17 | ) 18 | ) 19 | 20 | ThisBuild / description := "openapi-generator sbt plugin." 21 | ThisBuild / licenses := List( 22 | "Apache 2" -> new URL("http://www.apache.org/licenses/LICENSE-2.0.txt") 23 | ) 24 | ThisBuild / homepage := Some(url("https://github.com/openapitools/sbt-openapi-generator")) 25 | 26 | // Remove all additional repository other than Maven Central from POM 27 | ThisBuild / pomIncludeRepository := { _ => false } 28 | ThisBuild / publishTo := { 29 | // For accounts created after Feb 2021: 30 | // val nexus = "https://s01.oss.sonatype.org/" 31 | val nexus = "https://oss.sonatype.org/" 32 | //if (isSnapshot.value) Some("snapshots" at nexus + "content/repositories/snapshots") 33 | //else Some("releases" at nexus + "service/local/staging/deploy/maven2") 34 | Some("releases" at nexus + "service/local/staging/deploy/maven2") 35 | } 36 | ThisBuild / publishMavenStyle := true 37 | -------------------------------------------------------------------------------- /src/main/scala/org/openapitools/generator/sbt/plugin/OpenApiGeneratorKeys.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 OpenAPI-Generator Contributors (https://openapi-generator.tech) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * 7 | * You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package org.openapitools.generator.sbt.plugin 19 | 20 | import org.openapitools.codegen.CodegenConstants 21 | import sbt.{File, settingKey, taskKey} 22 | 23 | trait OpenApiGeneratorKeys { 24 | final val openApiGenerate = taskKey[Seq[File]]("Generate code via Open API Tools Generator for Open API 2.0 or 3.x specification documents.") 25 | final val openApiGenerators = taskKey[Unit]("Print list of available generators") 26 | 27 | final val openApiInputSpec = settingKey[String]("The Open API 2.0/3.x specification location.") 28 | final val openApiOutputDir = settingKey[String]("The output target directory into which code will be generated.") 29 | final val openApiConfigFile = settingKey[String]("Path to json configuration file.\n" + 30 | "File content should be in a json format { \"optionKey\":\"optionValue\", \"optionKey1\":\"optionValue1\"...}\n" + 31 | "Supported options can be different for each language. Run config-help -g {generator name} command for language specific config options.") 32 | final val openApiAdditionalProperties = settingKey[Map[String, String]]("Sets additional properties that can be referenced by the mustache templates in the format of name=value,name=value.\n" + 33 | "You can also have multiple occurrences of this option.") 34 | @deprecated("use openApiGlobalProperties instead") final val openApiSystemProperties = settingKey[Map[String, String]]("Sets specified system properties.") 35 | final val openApiGlobalProperties = settingKey[Map[String, String]]("Sets specified system properties.") 36 | 37 | final val openApiVerbose = settingKey[Option[Boolean]]("The verbosity of generation") 38 | final val openApiValidateSpec = settingKey[Option[Boolean]]("Whether or not an input specification should be validated upon generation.") 39 | final val openApiGeneratorName = settingKey[String]("The name of the generator which will handle codegen. (see \"openApiGenerators\" task)") 40 | final val openApiTemplateDir = settingKey[String]("The template directory holding a custom template.") 41 | final val openApiAuth = settingKey[String]("Adds authorization headers when fetching the OpenAPI definitions remotely.\n" + 42 | "Pass in a URL-encoded string of name:header with a comma separating multiple values") 43 | final val openApiSkipOverwrite = settingKey[Option[Boolean]]("Specifies if the existing files should be overwritten during the generation.") 44 | final val openApiPackageName = settingKey[String](CodegenConstants.PACKAGE_NAME_DESC) 45 | final val openApiApiPackage = settingKey[String](CodegenConstants.API_PACKAGE_DESC) 46 | final val openApiModelPackage = settingKey[String](CodegenConstants.MODEL_PACKAGE_DESC) 47 | final val openApiModelNamePrefix = settingKey[String](CodegenConstants.MODEL_NAME_PREFIX_DESC) 48 | final val openApiModelNameSuffix = settingKey[String](CodegenConstants.MODEL_NAME_SUFFIX_DESC) 49 | final val openApiInstantiationTypes = settingKey[Map[String, String]]("Sets instantiation type mappings.") 50 | final val openApiTypeMappings = settingKey[Map[String, String]]("Sets mappings between OpenAPI spec types and generated code types.") 51 | final val openApiServerVariables = settingKey[Map[String, String]]("Sets server variable for server URL template substitution, in the format of name=value,name=value.\n" 52 | + "You can also have multiple occurrences of this option.") 53 | 54 | final val openApiLanguageSpecificPrimitives = settingKey[List[String]]("Specifies additional language specific primitive types in the format of type1,type2,type3,type3. For example: String,boolean,Boolean,Double.") 55 | final val openApiImportMappings = settingKey[Map[String, String]]("Specifies mappings between a given class and the import that should be used for that class.") 56 | final val openApiInvokerPackage = settingKey[String](CodegenConstants.INVOKER_PACKAGE_DESC) 57 | //TODO: change to sbt organization 58 | final val openApiGroupId = settingKey[String](CodegenConstants.GROUP_ID_DESC) 59 | //TODO: change to sbt name 60 | final val openApiId = settingKey[String](CodegenConstants.ARTIFACT_ID_DESC) 61 | 62 | final val openApiLibrary = settingKey[String](CodegenConstants.LIBRARY_DESC) 63 | final val openApiGitHost = settingKey[String](CodegenConstants.GIT_HOST_DESC) 64 | final val openApiGitUserId = settingKey[String](CodegenConstants.GIT_USER_ID_DESC) 65 | final val openApiGitRepoId = settingKey[String](CodegenConstants.GIT_REPO_ID_DESC) 66 | final val openApiReleaseNote = settingKey[String](CodegenConstants.RELEASE_NOTE_DESC) 67 | final val openApiHttpUserAgent = settingKey[String](CodegenConstants.HTTP_USER_AGENT_DESC) 68 | final val openApiReservedWordsMappings = settingKey[Map[String, String]]("Specifies how a reserved name should be escaped to.") 69 | final val openApiIgnoreFileOverride = settingKey[String](CodegenConstants.IGNORE_FILE_OVERRIDE_DESC) 70 | final val openApiRemoveOperationIdPrefix = settingKey[Option[Boolean]]("Remove prefix of operationId, e.g. config_getId => getId") 71 | 72 | /** 73 | * Defines which API-related files should be generated. This allows you to create a subset of generated files (or none at all). 74 | * 75 | * This option enables/disables generation of ALL api-related files. 76 | * 77 | * NOTE: Configuring any one of [apiFilesConstrainedTo], [modelFilesConstrainedTo], or [supportingFilesConstrainedTo] results 78 | * in others being disabled. That is, OpenAPI Generator considers any one of these to define a subset of generation. 79 | * For more control over generation of individual files, configure an ignore file and refer to it via [ignoreFileOverride]. 80 | */ 81 | final val openApiApiFilesConstrainedTo = settingKey[List[String]]("Defines which API-related files should be generated. This allows you to create a subset of generated files (or none at all).") 82 | 83 | /** 84 | * Defines which model-related files should be generated. This allows you to create a subset of generated files (or none at all). 85 | * 86 | * NOTE: Configuring any one of [apiFilesConstrainedTo], [modelFilesConstrainedTo], or [supportingFilesConstrainedTo] results 87 | * in others being disabled. That is, OpenAPI Generator considers any one of these to define a subset of generation. 88 | * For more control over generation of individual files, configure an ignore file and refer to it via [ignoreFileOverride]. 89 | */ 90 | final val openApiModelFilesConstrainedTo = settingKey[List[String]]("Defines which model-related files should be generated. This allows you to create a subset of generated files (or none at all).") 91 | 92 | /** 93 | * Defines which supporting files should be generated. This allows you to create a subset of generated files (or none at all). 94 | * 95 | * Supporting files are those related to projects/frameworks which may be modified 96 | * by consumers. 97 | * 98 | * NOTE: Configuring any one of [apiFilesConstrainedTo], [modelFilesConstrainedTo], or [supportingFilesConstrainedTo] results 99 | * in others being disabled. That is, OpenAPI Generator considers any one of these to define a subset of generation. 100 | * For more control over generation of individual files, configure an ignore file and refer to it via [ignoreFileOverride]. 101 | */ 102 | final val openApiSupportingFilesConstrainedTo = settingKey[List[String]]("Defines which supporting files should be generated. This allows you to create a subset of generated files (or none at all).") 103 | 104 | /** 105 | * Defines whether or not model-related _test_ files should be generated. 106 | * 107 | * This option enables/disables generation of ALL model-related _test_ files. 108 | * 109 | * For more control over generation of individual files, configure an ignore file and 110 | * refer to it via [ignoreFileOverride]. 111 | */ 112 | final val openApiGenerateModelTests = settingKey[Option[Boolean]](CodegenConstants.GENERATE_MODEL_TESTS_DESC) 113 | 114 | /** 115 | * Defines whether or not model-related _documentation_ files should be generated. 116 | * 117 | * This option enables/disables generation of ALL model-related _documentation_ files. 118 | * 119 | * For more control over generation of individual files, configure an ignore file and 120 | * refer to it via [ignoreFileOverride]. 121 | */ 122 | final val openApiGenerateModelDocumentation = settingKey[Option[Boolean]]("Defines whether or not model-related _documentation_ files should be generated.") 123 | 124 | /** 125 | * Defines whether or not api-related _test_ files should be generated. 126 | * 127 | * This option enables/disables generation of ALL api-related _test_ files. 128 | * 129 | * For more control over generation of individual files, configure an ignore file and 130 | * refer to it via [ignoreFileOverride]. 131 | */ 132 | final val openApiGenerateApiTests = settingKey[Option[Boolean]](CodegenConstants.GENERATE_API_TESTS_DESC) 133 | 134 | /** 135 | * Defines whether or not api-related _documentation_ files should be generated. 136 | * 137 | * This option enables/disables generation of ALL api-related _documentation_ files. 138 | * 139 | * For more control over generation of individual files, configure an ignore file and 140 | * refer to it via [ignoreFileOverride]. 141 | */ 142 | final val openApiGenerateApiDocumentation = settingKey[Option[Boolean]]("Defines whether or not api-related _documentation_ files should be generated.") 143 | final val openApiWithXml = settingKey[Option[Boolean]]("A special-case setting which configures some generators with XML support. In some cases, this forces json OR xml, so the default here is false.") 144 | 145 | final val openApiLogToStderr = settingKey[Option[Boolean]]("To write all log messages (not just errors) to STDOUT") 146 | 147 | /** 148 | * To enable the file post-processing hook. This enables executing an external post-processor (usually a linter program). 149 | * This only enables the post-processor. To define the post-processing command, define an environment variable such as 150 | * LANG_POST_PROCESS_FILE (e.g. GO_POST_PROCESS_FILE, SCALA_POST_PROCESS_FILE). Please open an issue if your target 151 | * generator does not support this functionality. 152 | */ 153 | final val openApiEnablePostProcessFile = settingKey[Option[Boolean]](CodegenConstants.ENABLE_POST_PROCESS_FILE_DESC) 154 | 155 | final val openApiSkipValidateSpec = settingKey[Option[Boolean]]("To skip spec validation. When true, we will skip the default behavior of validating a spec before generation.") 156 | 157 | /** 158 | * To generate alias (array, list, map) as model. When false, top-level objects defined as array, list, or map will result in those 159 | * definitions generated as top-level Array-of-items, List-of-items, Map-of-items definitions. 160 | * When true, A model representation either containing or extending the array,list,map (depending on specific generator implementation) will be generated. 161 | */ 162 | final val openApiGenerateAliasAsModel = settingKey[Option[Boolean]](CodegenConstants.GENERATE_ALIAS_AS_MODEL_DESC) 163 | 164 | /** 165 | * Indicate whether or not to generate OpenAPI Generator metadata files. 166 | * These files include .openapi-generator/VERSION, .openapi-generator-ignore, and any other metadata files 167 | * used by OpenAPI Generator. 168 | */ 169 | final val openApiGenerateMetadata = settingKey[Option[Boolean]]("Generate metadata files used by OpenAPI Generator. This includes .openapi-generator-ignore and any files within .openapi-generator.") 170 | 171 | } 172 | -------------------------------------------------------------------------------- /src/main/scala/org/openapitools/generator/sbt/plugin/OpenApiGeneratorPlugin.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 OpenAPI-Generator Contributors (https://openapi-generator.tech) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * 7 | * You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package org.openapitools.generator.sbt.plugin 19 | 20 | import org.openapitools.generator.sbt.plugin.tasks.{OpenApiGenerateTask, OpenApiGeneratorsTask} 21 | import sbt.Keys.aggregate 22 | import sbt.plugins.JvmPlugin 23 | import sbt.{Def, File, config, taskKey} 24 | 25 | object OpenApiGeneratorPlugin extends sbt.AutoPlugin 26 | with OpenApiGeneratorsTask 27 | with OpenApiGenerateTask { 28 | self => 29 | 30 | override def requires: JvmPlugin.type = sbt.plugins.JvmPlugin 31 | 32 | override def trigger: sbt.PluginTrigger = allRequirements 33 | 34 | object autoImport extends OpenApiGeneratorKeys { 35 | 36 | def SettingEnabled: Option[Boolean] = Some(true) 37 | 38 | def SettingDisabled: Option[Boolean] = Some(false) 39 | 40 | 41 | } 42 | 43 | val out = taskKey[Seq[File]]("Out") 44 | 45 | val OpenApiCodegen = config("openApiCodegen") 46 | 47 | override def globalSettings: Seq[Def.Setting[_]] = Seq( 48 | aggregate in openApiGenerators := false 49 | ) 50 | 51 | private lazy val baseSettings: Seq[sbt.Setting[_]] = Seq[sbt.Setting[_]]( 52 | openApiInputSpec := "", 53 | openApiOutputDir := "", 54 | openApiConfigFile := "", 55 | openApiAdditionalProperties := Map.empty[String, String], 56 | openApiSystemProperties := Map.empty[String, String], 57 | openApiGlobalProperties := Map.empty[String, String], 58 | openApiVerbose := None, 59 | openApiValidateSpec := None, 60 | openApiGeneratorName := "", 61 | openApiTemplateDir := "", 62 | openApiAuth := "", 63 | openApiSkipOverwrite := None, 64 | openApiPackageName := "", 65 | openApiApiPackage := "", 66 | openApiModelPackage := "", 67 | openApiModelNamePrefix := "", 68 | openApiModelNameSuffix := "", 69 | openApiInstantiationTypes := Map.empty[String, String], 70 | openApiTypeMappings := Map.empty[String, String], 71 | openApiServerVariables := Map.empty[String, String], 72 | openApiLanguageSpecificPrimitives := List[String](), 73 | openApiImportMappings := Map.empty[String, String], 74 | openApiInvokerPackage := "", 75 | openApiGroupId := "", 76 | openApiId := "", 77 | openApiLibrary := "", 78 | openApiGitHost := "", 79 | openApiGitUserId := "", 80 | openApiGitRepoId := "", 81 | openApiReleaseNote := "", 82 | openApiHttpUserAgent := "", 83 | openApiReservedWordsMappings := Map.empty[String, String], 84 | openApiIgnoreFileOverride := "", 85 | openApiRemoveOperationIdPrefix := None, 86 | openApiApiFilesConstrainedTo := List[String](), 87 | openApiModelFilesConstrainedTo := List[String](), 88 | openApiSupportingFilesConstrainedTo := List[String](), 89 | openApiGenerateModelTests := None, 90 | openApiGenerateModelDocumentation := None, 91 | openApiGenerateApiTests := None, 92 | openApiGenerateApiDocumentation := None, 93 | openApiWithXml := None, 94 | openApiLogToStderr := None, 95 | openApiEnablePostProcessFile := None, 96 | openApiSkipValidateSpec := None, 97 | openApiGenerateAliasAsModel := None, 98 | openApiGenerateMetadata := None 99 | ) 100 | 101 | override lazy val projectSettings: Seq[Def.Setting[_]] = Seq[sbt.Setting[_]]( 102 | openApiGenerators := openApiGeneratorsTask.value, 103 | openApiGenerate := openApiGenerateTask.value 104 | ) ++ baseSettings 105 | 106 | } 107 | -------------------------------------------------------------------------------- /src/main/scala/org/openapitools/generator/sbt/plugin/tasks/OpenApiGenerateTask.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 OpenAPI-Generator Contributors (https://openapi-generator.tech) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * 7 | * You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.openapitools.generator.sbt.plugin.tasks 18 | 19 | import org.openapitools.codegen.config.{CodegenConfigurator, GlobalSettings} 20 | import org.openapitools.codegen.{CodegenConstants, DefaultGenerator} 21 | import org.openapitools.generator.sbt.plugin.OpenApiGeneratorKeys 22 | import sbt.Keys._ 23 | import sbt.{Def, _} 24 | 25 | import scala.collection.JavaConverters._ 26 | import scala.util.{Failure, Success, Try} 27 | 28 | trait OpenApiGenerateTask extends OpenApiGeneratorKeys { 29 | 30 | protected[this] def openApiGenerateTask: Def.Initialize[Task[Seq[File]]] = Def.task { 31 | 32 | val logger = sbt.Keys.streams.value.log 33 | 34 | if (openApiConfigFile.value.isEmpty && openApiGeneratorName.value.isEmpty) { 35 | Seq() 36 | } else { 37 | val configurator: CodegenConfigurator = if (openApiConfigFile.value.nonEmpty) { 38 | val config = openApiConfigFile.value 39 | logger.info(s"read configuration from $config") 40 | CodegenConfigurator.fromFile(config) 41 | } else new CodegenConfigurator() 42 | 43 | if (openApiSupportingFilesConstrainedTo.value.nonEmpty) { 44 | GlobalSettings.setProperty(CodegenConstants.SUPPORTING_FILES, openApiSupportingFilesConstrainedTo.value.mkString(",")) 45 | } else { 46 | GlobalSettings.clearProperty(CodegenConstants.SUPPORTING_FILES) 47 | } 48 | 49 | if (openApiModelFilesConstrainedTo.value.nonEmpty) { 50 | GlobalSettings.setProperty(CodegenConstants.MODELS, openApiModelFilesConstrainedTo.value.mkString(",")) 51 | } else { 52 | GlobalSettings.clearProperty(CodegenConstants.MODELS) 53 | } 54 | 55 | if (openApiApiFilesConstrainedTo.value.nonEmpty) { 56 | GlobalSettings.setProperty(CodegenConstants.APIS, openApiApiFilesConstrainedTo.value.mkString(",")) 57 | } else { 58 | GlobalSettings.clearProperty(CodegenConstants.APIS) 59 | } 60 | 61 | openApiGenerateApiDocumentation.value.foreach { value => 62 | GlobalSettings.setProperty(CodegenConstants.API_DOCS, value.toString) 63 | } 64 | 65 | openApiGenerateModelDocumentation.value.foreach { value => 66 | GlobalSettings.setProperty(CodegenConstants.MODEL_DOCS, value.toString) 67 | } 68 | 69 | openApiGenerateModelTests.value.foreach { value => 70 | GlobalSettings.setProperty(CodegenConstants.MODEL_TESTS, value.toString) 71 | } 72 | 73 | openApiGenerateApiTests.value.foreach { value => 74 | GlobalSettings.setProperty(CodegenConstants.API_TESTS, value.toString) 75 | } 76 | 77 | openApiWithXml.value.foreach { value => 78 | GlobalSettings.setProperty(CodegenConstants.WITH_XML, value.toString) 79 | } 80 | 81 | // now override with any specified parameters 82 | openApiVerbose.value.foreach { value => 83 | configurator.setVerbose(value) 84 | } 85 | openApiValidateSpec.value.foreach { value => 86 | configurator.setValidateSpec(value) 87 | } 88 | 89 | openApiSkipOverwrite.value.foreach { value => 90 | configurator.setSkipOverwrite(value) 91 | } 92 | 93 | if (openApiInputSpec.value.nonEmpty) { 94 | configurator.setInputSpec(openApiInputSpec.value) 95 | } 96 | 97 | 98 | if (openApiGeneratorName.value.nonEmpty) { 99 | configurator.setGeneratorName(openApiGeneratorName.value) 100 | } 101 | 102 | if (openApiOutputDir.value.nonEmpty) { 103 | configurator.setOutputDir(openApiOutputDir.value) 104 | } 105 | 106 | if (openApiAuth.value.nonEmpty) { 107 | configurator.setAuth(openApiAuth.value) 108 | } 109 | 110 | if (openApiTemplateDir.value.nonEmpty) { 111 | configurator.setTemplateDir(openApiTemplateDir.value) 112 | } 113 | 114 | if (openApiPackageName.value.nonEmpty) { 115 | configurator.setPackageName(openApiPackageName.value) 116 | } 117 | 118 | if (openApiApiPackage.value.nonEmpty) { 119 | configurator.setApiPackage(openApiApiPackage.value) 120 | } 121 | 122 | if (openApiModelPackage.value.nonEmpty) { 123 | configurator.setModelPackage(openApiModelPackage.value) 124 | } 125 | 126 | if (openApiModelNamePrefix.value.nonEmpty) { 127 | configurator.setModelNamePrefix(openApiModelNamePrefix.value) 128 | } 129 | 130 | if (openApiModelNameSuffix.value.nonEmpty) { 131 | configurator.setModelNameSuffix(openApiModelNameSuffix.value) 132 | } 133 | 134 | if (openApiInvokerPackage.value.nonEmpty) { 135 | configurator.setInvokerPackage(openApiInvokerPackage.value) 136 | } 137 | 138 | if (openApiGroupId.value.nonEmpty) { 139 | configurator.setGroupId(openApiGroupId.value) 140 | } 141 | 142 | if (openApiId.value.nonEmpty) { 143 | configurator.setArtifactId(openApiId.value) 144 | } 145 | 146 | if ((version in openApiGenerate).value.nonEmpty) { 147 | configurator.setArtifactVersion(version.value) 148 | } 149 | 150 | if (openApiLibrary.value.nonEmpty) { 151 | configurator.setLibrary(openApiLibrary.value) 152 | } 153 | 154 | if (openApiGitHost.value.nonEmpty) { 155 | configurator.setGitHost(openApiGitHost.value) 156 | } 157 | 158 | if (openApiGitUserId.value.nonEmpty) { 159 | configurator.setGitUserId(openApiGitUserId.value) 160 | } 161 | 162 | 163 | if (openApiGitRepoId.value.nonEmpty) { 164 | configurator.setGitRepoId(openApiGitRepoId.value) 165 | } 166 | 167 | if (openApiReleaseNote.value.nonEmpty) { 168 | configurator.setReleaseNote(openApiReleaseNote.value) 169 | } 170 | 171 | if (openApiHttpUserAgent.value.nonEmpty) { 172 | configurator.setHttpUserAgent(openApiHttpUserAgent.value) 173 | } 174 | 175 | if (openApiIgnoreFileOverride.value.nonEmpty) { 176 | configurator.setIgnoreFileOverride(openApiIgnoreFileOverride.value) 177 | } 178 | 179 | openApiRemoveOperationIdPrefix.value.foreach { value => 180 | configurator.setRemoveOperationIdPrefix(value) 181 | } 182 | 183 | openApiLogToStderr.value.foreach { value => 184 | configurator.setLogToStderr(value) 185 | } 186 | 187 | openApiEnablePostProcessFile.value.foreach { value => 188 | configurator.setEnablePostProcessFile(value) 189 | } 190 | 191 | openApiSkipValidateSpec.value.foreach { value => 192 | configurator.setValidateSpec(!value) 193 | } 194 | 195 | openApiGenerateAliasAsModel.value.foreach { value => 196 | configurator.setGenerateAliasAsModel(value) 197 | } 198 | 199 | if (openApiGlobalProperties.value.nonEmpty || openApiSystemProperties.value.nonEmpty) { 200 | (openApiSystemProperties.value ++ openApiGlobalProperties.value).foreach { entry => 201 | configurator.addGlobalProperty(entry._1, entry._2) 202 | } 203 | } 204 | 205 | if (openApiInstantiationTypes.value.nonEmpty) { 206 | openApiInstantiationTypes.value.foreach { entry => 207 | configurator.addInstantiationType(entry._1, entry._2) 208 | } 209 | } 210 | 211 | if (openApiImportMappings.value.nonEmpty) { 212 | openApiImportMappings.value.foreach { entry => 213 | configurator.addImportMapping(entry._1, entry._2) 214 | } 215 | } 216 | 217 | if (openApiTypeMappings.value.nonEmpty) { 218 | openApiTypeMappings.value.foreach { entry => 219 | configurator.addTypeMapping(entry._1, entry._2) 220 | } 221 | } 222 | 223 | if (openApiAdditionalProperties.value.nonEmpty) { 224 | openApiAdditionalProperties.value.foreach { entry => 225 | configurator.addAdditionalProperty(entry._1, entry._2) 226 | } 227 | } 228 | 229 | if (openApiServerVariables.value.nonEmpty) { 230 | openApiServerVariables.value.foreach { entry => 231 | configurator.addServerVariable(entry._1, entry._2) 232 | } 233 | } 234 | 235 | if (openApiLanguageSpecificPrimitives.value.nonEmpty) { 236 | openApiLanguageSpecificPrimitives.value.foreach { it => 237 | configurator.addLanguageSpecificPrimitive(it) 238 | } 239 | } 240 | 241 | if (openApiReservedWordsMappings.value.nonEmpty) { 242 | openApiReservedWordsMappings.value.foreach { entry => 243 | configurator.addAdditionalReservedWordMapping(entry._1, entry._2) 244 | } 245 | } 246 | 247 | Try(configurator.toClientOptInput) match { 248 | case Success(clientOptInput) => 249 | Try { 250 | val gen = new DefaultGenerator() 251 | 252 | gen.opts(clientOptInput) 253 | 254 | openApiGenerateMetadata.value.foreach { value => 255 | gen.setGenerateMetadata(value) 256 | } 257 | 258 | val res = gen.generate().asScala 259 | 260 | logger.info(s"Successfully generated code to ${clientOptInput.getConfig.getOutputDir}") 261 | res 262 | } match { 263 | case Success(value) => value 264 | case Failure(ex) => 265 | throw new Exception("Code generation failed.", ex) 266 | } 267 | case Failure(ex) => 268 | logger.error(ex.getMessage) 269 | Seq.empty 270 | } 271 | } 272 | } 273 | } 274 | -------------------------------------------------------------------------------- /src/main/scala/org/openapitools/generator/sbt/plugin/tasks/OpenApiGeneratorsTask.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020 OpenAPI-Generator Contributors (https://openapi-generator.tech) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * 7 | * You may obtain a copy of the License at 8 | * 9 | * https://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package org.openapitools.generator.sbt.plugin.tasks 19 | 20 | import org.openapitools.codegen.meta.Stability 21 | import org.openapitools.codegen.{CodegenConfigLoader, CodegenType} 22 | import sbt.{Def, Task} 23 | 24 | import scala.collection.JavaConverters._ 25 | 26 | trait OpenApiGeneratorsTask { 27 | 28 | protected[this] def openApiGeneratorsTask: Def.Initialize[Task[Unit]] = Def.task { 29 | val generators = CodegenConfigLoader.getAll.asScala 30 | val types = CodegenType.values() 31 | 32 | val stabilities = Stability.values().filterNot { 33 | _ == Stability.DEPRECATED 34 | } 35 | 36 | val out = new StringBuilder 37 | 38 | out ++= "The following generators are available:" + System.lineSeparator() 39 | for (t <- types) { 40 | val filteredGenerators = generators.filter(_.getTag == t).sortBy(_.getName) 41 | if (filteredGenerators.nonEmpty) { 42 | out ++= s" $t generators:" + System.lineSeparator() 43 | filteredGenerators.foreach { 44 | generator => 45 | val meta = generator.getGeneratorMetadata 46 | val stability = meta.getStability 47 | val include = stabilities.contains(stability) 48 | if (include) { 49 | out ++= s" - ${generator.getName}" 50 | if (stability != Stability.STABLE) { 51 | out ++= s" (${stability.value()})" 52 | } 53 | out ++= System.lineSeparator() 54 | } 55 | } 56 | } 57 | } 58 | out ++= System.lineSeparator() 59 | out ++= System.lineSeparator() 60 | 61 | println(out) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-openapi-generator/simple/build.sbt: -------------------------------------------------------------------------------- 1 | scalaVersion := "2.12.10" 2 | 3 | externalResolvers += Resolver.sonatypeRepo("snapshots") 4 | 5 | lazy val generated = project.in(file("generated")) 6 | .enablePlugins(OpenApiGeneratorPlugin) 7 | .settings( 8 | openApiInputSpec := "openapi.yaml", 9 | openApiConfigFile := "config.yaml", 10 | openApiValidateSpec := SettingDisabled, 11 | openApiGenerateModelTests := SettingEnabled 12 | ) 13 | 14 | lazy val root = (project in file(".")) 15 | .settings( 16 | name := "openapi-generator-example" 17 | ) 18 | .dependsOn(generated) 19 | .aggregate(generated) 20 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-openapi-generator/simple/config.yaml: -------------------------------------------------------------------------------- 1 | apiPackage: "org.openapitools.client.custom.api" 2 | generatorName: "scala-akka" 3 | outputDir : "generated" 4 | additionalProperties: 5 | dateLibrary: "joda" 6 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-openapi-generator/simple/openapi.yaml: -------------------------------------------------------------------------------- 1 | openapi: 3.0.1 2 | info: 3 | title: Swagger Petstore 4 | description: 'This is a sample server Petstore server. You can find out more about Swagger 5 | at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For 6 | this sample, you can use the api key `special-key` to test the authorization filters.' 7 | termsOfService: http://swagger.io/terms/ 8 | contact: 9 | email: apiteam@swagger.io 10 | license: 11 | name: Apache 2.0 12 | url: http://www.apache.org/licenses/LICENSE-2.0.html 13 | version: 1.0.0 14 | externalDocs: 15 | description: Find out more about Swagger 16 | url: http://swagger.io 17 | servers: 18 | - url: https://petstore.swagger.io/v2 19 | - url: http://petstore.swagger.io/v2 20 | tags: 21 | - name: pet 22 | description: Everything about your Pets 23 | externalDocs: 24 | description: Find out more 25 | url: http://swagger.io 26 | - name: store 27 | description: Access to Petstore orders 28 | - name: user 29 | description: Operations about user 30 | externalDocs: 31 | description: Find out more about our store 32 | url: http://swagger.io 33 | paths: 34 | /pet: 35 | put: 36 | tags: 37 | - pet 38 | summary: Update an existing pet 39 | operationId: updatePet 40 | requestBody: 41 | description: Pet object that needs to be added to the store 42 | content: 43 | application/json: 44 | schema: 45 | $ref: '#/components/schemas/Pet' 46 | application/xml: 47 | schema: 48 | $ref: '#/components/schemas/Pet' 49 | required: true 50 | responses: 51 | 400: 52 | description: Invalid ID supplied 53 | content: {} 54 | 404: 55 | description: Pet not found 56 | content: {} 57 | 405: 58 | description: Validation exception 59 | content: {} 60 | security: 61 | - petstore_auth: 62 | - write:pets 63 | - read:pets 64 | post: 65 | tags: 66 | - pet 67 | summary: Add a new pet to the store 68 | operationId: addPet 69 | requestBody: 70 | description: Pet object that needs to be added to the store 71 | content: 72 | application/json: 73 | schema: 74 | $ref: '#/components/schemas/Pet' 75 | application/xml: 76 | schema: 77 | $ref: '#/components/schemas/Pet' 78 | required: true 79 | responses: 80 | 405: 81 | description: Invalid input 82 | content: {} 83 | security: 84 | - petstore_auth: 85 | - write:pets 86 | - read:pets 87 | /pet/findByStatus: 88 | get: 89 | tags: 90 | - pet 91 | summary: Finds Pets by status 92 | description: Multiple status values can be provided with comma separated strings 93 | operationId: findPetsByStatus 94 | parameters: 95 | - name: status 96 | in: query 97 | description: Status values that need to be considered for filter 98 | required: true 99 | style: form 100 | explode: true 101 | schema: 102 | type: array 103 | items: 104 | type: string 105 | default: available 106 | enum: 107 | - available 108 | - pending 109 | - sold 110 | responses: 111 | 200: 112 | description: successful operation 113 | content: 114 | application/xml: 115 | schema: 116 | type: array 117 | items: 118 | $ref: '#/components/schemas/Pet' 119 | application/json: 120 | schema: 121 | type: array 122 | items: 123 | $ref: '#/components/schemas/Pet' 124 | 400: 125 | description: Invalid status value 126 | content: {} 127 | security: 128 | - petstore_auth: 129 | - write:pets 130 | - read:pets 131 | /pet/findByTags: 132 | get: 133 | tags: 134 | - pet 135 | summary: Finds Pets by tags 136 | description: Muliple tags can be provided with comma separated strings. Use tag1, 137 | tag2, tag3 for testing. 138 | operationId: findPetsByTags 139 | parameters: 140 | - name: tags 141 | in: query 142 | description: Tags to filter by 143 | required: true 144 | style: form 145 | explode: true 146 | schema: 147 | type: array 148 | items: 149 | type: string 150 | responses: 151 | 200: 152 | description: successful operation 153 | content: 154 | application/xml: 155 | schema: 156 | type: array 157 | items: 158 | $ref: '#/components/schemas/Pet' 159 | application/json: 160 | schema: 161 | type: array 162 | items: 163 | $ref: '#/components/schemas/Pet' 164 | 400: 165 | description: Invalid tag value 166 | content: {} 167 | deprecated: true 168 | security: 169 | - petstore_auth: 170 | - write:pets 171 | - read:pets 172 | /pet/{petId}: 173 | get: 174 | tags: 175 | - pet 176 | summary: Find pet by ID 177 | description: Returns a single pet 178 | operationId: getPetById 179 | parameters: 180 | - name: petId 181 | in: path 182 | description: ID of pet to return 183 | required: true 184 | schema: 185 | type: integer 186 | format: int64 187 | responses: 188 | 200: 189 | description: successful operation 190 | content: 191 | application/xml: 192 | schema: 193 | $ref: '#/components/schemas/Pet' 194 | application/json: 195 | schema: 196 | $ref: '#/components/schemas/Pet' 197 | 400: 198 | description: Invalid ID supplied 199 | content: {} 200 | 404: 201 | description: Pet not found 202 | content: {} 203 | security: 204 | - api_key: [] 205 | post: 206 | tags: 207 | - pet 208 | summary: Updates a pet in the store with form data 209 | operationId: updatePetWithForm 210 | parameters: 211 | - name: petId 212 | in: path 213 | description: ID of pet that needs to be updated 214 | required: true 215 | schema: 216 | type: integer 217 | format: int64 218 | requestBody: 219 | content: 220 | application/x-www-form-urlencoded: 221 | schema: 222 | properties: 223 | name: 224 | type: string 225 | description: Updated name of the pet 226 | status: 227 | type: string 228 | description: Updated status of the pet 229 | responses: 230 | 405: 231 | description: Invalid input 232 | content: {} 233 | security: 234 | - petstore_auth: 235 | - write:pets 236 | - read:pets 237 | delete: 238 | tags: 239 | - pet 240 | summary: Deletes a pet 241 | operationId: deletePet 242 | parameters: 243 | - name: api_key 244 | in: header 245 | schema: 246 | type: string 247 | - name: petId 248 | in: path 249 | description: Pet id to delete 250 | required: true 251 | schema: 252 | type: integer 253 | format: int64 254 | responses: 255 | 400: 256 | description: Invalid ID supplied 257 | content: {} 258 | 404: 259 | description: Pet not found 260 | content: {} 261 | security: 262 | - petstore_auth: 263 | - write:pets 264 | - read:pets 265 | /pet/{petId}/uploadImage: 266 | post: 267 | tags: 268 | - pet 269 | summary: uploads an image 270 | operationId: uploadFile 271 | parameters: 272 | - name: petId 273 | in: path 274 | description: ID of pet to update 275 | required: true 276 | schema: 277 | type: integer 278 | format: int64 279 | requestBody: 280 | content: 281 | multipart/form-data: 282 | schema: 283 | properties: 284 | additionalMetadata: 285 | type: string 286 | description: Additional data to pass to server 287 | file: 288 | type: string 289 | description: file to upload 290 | format: binary 291 | responses: 292 | 200: 293 | description: successful operation 294 | content: 295 | application/json: 296 | schema: 297 | $ref: '#/components/schemas/ApiResponse' 298 | security: 299 | - petstore_auth: 300 | - write:pets 301 | - read:pets 302 | /store/inventory: 303 | get: 304 | tags: 305 | - store 306 | summary: Returns pet inventories by status 307 | description: Returns a map of status codes to quantities 308 | operationId: getInventory 309 | responses: 310 | 200: 311 | description: successful operation 312 | content: 313 | application/json: 314 | schema: 315 | type: object 316 | additionalProperties: 317 | type: integer 318 | format: int32 319 | security: 320 | - api_key: [] 321 | /store/order: 322 | post: 323 | tags: 324 | - store 325 | summary: Place an order for a pet 326 | operationId: placeOrder 327 | requestBody: 328 | description: order placed for purchasing the pet 329 | content: 330 | '*/*': 331 | schema: 332 | $ref: '#/components/schemas/Order' 333 | required: true 334 | responses: 335 | 200: 336 | description: successful operation 337 | content: 338 | application/xml: 339 | schema: 340 | $ref: '#/components/schemas/Order' 341 | application/json: 342 | schema: 343 | $ref: '#/components/schemas/Order' 344 | 400: 345 | description: Invalid Order 346 | content: {} 347 | /store/order/{orderId}: 348 | get: 349 | tags: 350 | - store 351 | summary: Find purchase order by ID 352 | description: For valid response try integer IDs with value >= 1 and <= 10. Other 353 | values will generated exceptions 354 | operationId: getOrderById 355 | parameters: 356 | - name: orderId 357 | in: path 358 | description: ID of pet that needs to be fetched 359 | required: true 360 | schema: 361 | maximum: 10.0 362 | minimum: 1.0 363 | type: integer 364 | format: int64 365 | responses: 366 | 200: 367 | description: successful operation 368 | content: 369 | application/xml: 370 | schema: 371 | $ref: '#/components/schemas/Order' 372 | application/json: 373 | schema: 374 | $ref: '#/components/schemas/Order' 375 | 400: 376 | description: Invalid ID supplied 377 | content: {} 378 | 404: 379 | description: Order not found 380 | content: {} 381 | delete: 382 | tags: 383 | - store 384 | summary: Delete purchase order by ID 385 | description: For valid response try integer IDs with positive integer value. Negative 386 | or non-integer values will generate API errors 387 | operationId: deleteOrder 388 | parameters: 389 | - name: orderId 390 | in: path 391 | description: ID of the order that needs to be deleted 392 | required: true 393 | schema: 394 | minimum: 1.0 395 | type: integer 396 | format: int64 397 | responses: 398 | 400: 399 | description: Invalid ID supplied 400 | content: {} 401 | 404: 402 | description: Order not found 403 | content: {} 404 | /user: 405 | post: 406 | tags: 407 | - user 408 | summary: Create user 409 | description: This can only be done by the logged in user. 410 | operationId: createUser 411 | requestBody: 412 | description: Created user object 413 | content: 414 | '*/*': 415 | schema: 416 | $ref: '#/components/schemas/User' 417 | required: true 418 | responses: 419 | default: 420 | description: successful operation 421 | content: {} 422 | /user/createWithArray: 423 | post: 424 | tags: 425 | - user 426 | summary: Creates list of users with given input array 427 | operationId: createUsersWithArrayInput 428 | requestBody: 429 | description: List of user object 430 | content: 431 | '*/*': 432 | schema: 433 | type: array 434 | items: 435 | $ref: '#/components/schemas/User' 436 | required: true 437 | responses: 438 | default: 439 | description: successful operation 440 | content: {} 441 | /user/createWithList: 442 | post: 443 | tags: 444 | - user 445 | summary: Creates list of users with given input array 446 | operationId: createUsersWithListInput 447 | requestBody: 448 | description: List of user object 449 | content: 450 | '*/*': 451 | schema: 452 | type: array 453 | items: 454 | $ref: '#/components/schemas/User' 455 | required: true 456 | responses: 457 | default: 458 | description: successful operation 459 | content: {} 460 | /user/login: 461 | get: 462 | tags: 463 | - user 464 | summary: Logs user into the system 465 | operationId: loginUser 466 | parameters: 467 | - name: username 468 | in: query 469 | description: The user name for login 470 | required: true 471 | schema: 472 | type: string 473 | - name: password 474 | in: query 475 | description: The password for login in clear text 476 | required: true 477 | schema: 478 | type: string 479 | responses: 480 | 200: 481 | description: successful operation 482 | headers: 483 | X-Rate-Limit: 484 | description: calls per hour allowed by the user 485 | schema: 486 | type: integer 487 | format: int32 488 | X-Expires-After: 489 | description: date in UTC when token expires 490 | schema: 491 | type: string 492 | format: date-time 493 | content: 494 | application/xml: 495 | schema: 496 | type: string 497 | application/json: 498 | schema: 499 | type: string 500 | 400: 501 | description: Invalid username/password supplied 502 | content: {} 503 | /user/logout: 504 | get: 505 | tags: 506 | - user 507 | summary: Logs out current logged in user session 508 | operationId: logoutUser 509 | responses: 510 | default: 511 | description: successful operation 512 | content: {} 513 | /user/{username}: 514 | get: 515 | tags: 516 | - user 517 | summary: Get user by user name 518 | operationId: getUserByName 519 | parameters: 520 | - name: username 521 | in: path 522 | description: 'The name that needs to be fetched. Use user1 for testing. ' 523 | required: true 524 | schema: 525 | type: string 526 | responses: 527 | 200: 528 | description: successful operation 529 | content: 530 | application/xml: 531 | schema: 532 | $ref: '#/components/schemas/User' 533 | application/json: 534 | schema: 535 | $ref: '#/components/schemas/User' 536 | 400: 537 | description: Invalid username supplied 538 | content: {} 539 | 404: 540 | description: User not found 541 | content: {} 542 | put: 543 | tags: 544 | - user 545 | summary: Updated user 546 | description: This can only be done by the logged in user. 547 | operationId: updateUser 548 | parameters: 549 | - name: username 550 | in: path 551 | description: name that need to be updated 552 | required: true 553 | schema: 554 | type: string 555 | requestBody: 556 | description: Updated user object 557 | content: 558 | '*/*': 559 | schema: 560 | $ref: '#/components/schemas/User' 561 | required: true 562 | responses: 563 | 400: 564 | description: Invalid user supplied 565 | content: {} 566 | 404: 567 | description: User not found 568 | content: {} 569 | delete: 570 | tags: 571 | - user 572 | summary: Delete user 573 | description: This can only be done by the logged in user. 574 | operationId: deleteUser 575 | parameters: 576 | - name: username 577 | in: path 578 | description: The name that needs to be deleted 579 | required: true 580 | schema: 581 | type: string 582 | responses: 583 | 400: 584 | description: Invalid username supplied 585 | content: {} 586 | 404: 587 | description: User not found 588 | content: {} 589 | components: 590 | schemas: 591 | Order: 592 | type: object 593 | properties: 594 | id: 595 | type: integer 596 | format: int64 597 | petId: 598 | type: integer 599 | format: int64 600 | quantity: 601 | type: integer 602 | format: int32 603 | shipDate: 604 | type: string 605 | format: date-time 606 | status: 607 | type: string 608 | description: Order Status 609 | enum: 610 | - placed 611 | - approved 612 | - delivered 613 | complete: 614 | type: boolean 615 | default: false 616 | xml: 617 | name: Order 618 | Category: 619 | type: object 620 | properties: 621 | id: 622 | type: integer 623 | format: int64 624 | name: 625 | type: string 626 | xml: 627 | name: Category 628 | User: 629 | type: object 630 | properties: 631 | id: 632 | type: integer 633 | format: int64 634 | username: 635 | type: string 636 | firstName: 637 | type: string 638 | lastName: 639 | type: string 640 | email: 641 | type: string 642 | password: 643 | type: string 644 | phone: 645 | type: string 646 | userStatus: 647 | type: integer 648 | description: User Status 649 | format: int32 650 | xml: 651 | name: User 652 | Tag: 653 | type: object 654 | properties: 655 | id: 656 | type: integer 657 | format: int64 658 | name: 659 | type: string 660 | xml: 661 | name: Tag 662 | Pet: 663 | required: 664 | - name 665 | - photoUrls 666 | type: object 667 | properties: 668 | id: 669 | type: integer 670 | format: int64 671 | category: 672 | $ref: '#/components/schemas/Category' 673 | name: 674 | type: string 675 | example: doggie 676 | photoUrls: 677 | type: array 678 | xml: 679 | name: photoUrl 680 | wrapped: true 681 | items: 682 | type: string 683 | tags: 684 | type: array 685 | xml: 686 | name: tag 687 | wrapped: true 688 | items: 689 | $ref: '#/components/schemas/Tag' 690 | status: 691 | type: string 692 | description: pet status in the store 693 | enum: 694 | - available 695 | - pending 696 | - sold 697 | xml: 698 | name: Pet 699 | ApiResponse: 700 | type: object 701 | properties: 702 | code: 703 | type: integer 704 | format: int32 705 | type: 706 | type: string 707 | message: 708 | type: string 709 | securitySchemes: 710 | petstore_auth: 711 | type: oauth2 712 | flows: 713 | implicit: 714 | authorizationUrl: http://petstore.swagger.io/oauth/dialog 715 | scopes: 716 | write:pets: modify pets in your account 717 | read:pets: read your pets 718 | api_key: 719 | type: apiKey 720 | name: api_key 721 | in: header 722 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-openapi-generator/simple/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.10.11 2 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-openapi-generator/simple/project/plugin.sbt: -------------------------------------------------------------------------------- 1 | resolvers ++= Seq( 2 | Resolver.sonatypeRepo("snapshots") 3 | ) 4 | sys.props.get("plugin.version") match { 5 | case Some(x) => addSbtPlugin("org.openapitools" % "sbt-openapi-generator" % x) 6 | case _ => 7 | throw new Exception("The system property 'plugin.version' is not defined.") 8 | } -------------------------------------------------------------------------------- /src/sbt-test/sbt-openapi-generator/simple/src/main/scala/Main.scala: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 OpenAPI-Generator Contributors (https://openapi-generator.tech) 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package simple.src.main.scala 18 | 19 | object Main extends App { 20 | println("hello world") 21 | } 22 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-openapi-generator/simple/test: -------------------------------------------------------------------------------- 1 | > openApiGenerators 2 | > openApiGenerate 3 | > reload 4 | $ exists generated/build.sbt 5 | $ exists generated/.openapi-generator-ignore 6 | $ exists generated/.openapi-generator/VERSION 7 | $ exists generated/src/main/scala/org/openapitools/client/core/ApiInvoker.scala 8 | $ exists generated/src/main/scala/org/openapitools/client/model/ApiResponse.scala 9 | $ exists generated/src/main/scala/org/openapitools/client/model/Category.scala 10 | $ exists generated/src/main/scala/org/openapitools/client/custom/api/PetApi.scala 11 | -------------------------------------------------------------------------------- /src/sbt-test/sbt-openapi-generator/simple/version.sbt: -------------------------------------------------------------------------------- 1 | version := "1.0.0" 2 | --------------------------------------------------------------------------------