[CLI] Initial implementation for batch generation (#3789)

* [CLI] Initial implementation for batch generation

Allows for generating multiple outputs via config. Just specify multiple
config files on command line.

Intent for this is to reduce CI times to generate outputs as well as to
reduce time for users to run ensure-up-to-date to meet PR standards.

Example command:

  openapi-generator batch --includes-base-dir `pwd` --fail-fast  -- bin/ci/*

---

As part of this implementation, the batch command support a customized
JSON key, `!include`. If this key's value refers to an existing file,
that file's contents are "unwrapped" into the config during
deserialization. This allows us to easily point to the same configs used
by our sample scripts without modifying the CLI generate task's switches
or assumptions.

* Allow for path-relative outputs
* Add batch JSON objects
* Include INFO log about threads used and includes/root
* Ensure GlobalSettings.reset()
* Improved thread-safety of ModelUtils
This commit is contained in:
Jim Schubert
2019-10-09 12:51:52 -04:00
committed by GitHub
parent 081383c886
commit 54d7e8c488
359 changed files with 3251 additions and 1586 deletions

View File

@@ -17,6 +17,9 @@ import java.io.File;
import openapitools.OpenAPIUtils;
import com.fasterxml.jackson.core.type.TypeReference;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.CompletableFuture;
import javax.validation.constraints.*;
import play.Configuration;
@@ -38,7 +41,7 @@ public class PetApiController extends Controller {
@ApiAction
public Result addPet() throws Exception {
public CompletionStage<Result> addPet() throws Exception {
JsonNode nodebody = request().body().asJson();
Pet body;
if (nodebody != null) {
@@ -49,12 +52,14 @@ public class PetApiController extends Controller {
} else {
throw new IllegalArgumentException("'body' parameter is required");
}
imp.addPet(body);
return ok();
return CompletableFuture.supplyAsync(() -> {
imp.addPet(body)
return ok();
});
}
@ApiAction
public Result deletePet(Long petId) throws Exception {
public CompletionStage<Result> deletePet(Long petId) throws Exception {
String valueapiKey = request().getHeader("api_key");
String apiKey;
if (valueapiKey != null) {
@@ -62,12 +67,14 @@ public class PetApiController extends Controller {
} else {
apiKey = null;
}
imp.deletePet(petId, apiKey);
return ok();
return CompletableFuture.supplyAsync(() -> {
imp.deletePet(petId, apiKey)
return ok();
});
}
@ApiAction
public Result findPetsByStatus() throws Exception {
public CompletionStage<Result> findPetsByStatus() throws Exception {
String[] statusArray = request().queryString().get("status");
if (statusArray == null) {
throw new IllegalArgumentException("'status' parameter is required");
@@ -80,18 +87,22 @@ public class PetApiController extends Controller {
status.add(curParam);
}
}
List<Pet> obj = imp.findPetsByStatus(status);
if (configuration.getBoolean("useOutputBeanValidation")) {
for (Pet curItem : obj) {
OpenAPIUtils.validate(curItem);
CompletionStage<List<Pet>> stage = imp.findPetsByStatus(status).thenApply(obj -> {
if (configuration.getBoolean("useOutputBeanValidation")) {
for (Pet curItem : obj) {
OpenAPIUtils.validate(curItem);
}
}
}
JsonNode result = mapper.valueToTree(obj);
return ok(result);
return obj;
});
stage.thenApply(obj -> {
JsonNode result = mapper.valueToTree(obj);
return ok(result);
});
}
@ApiAction
public Result findPetsByTags() throws Exception {
public CompletionStage<Result> findPetsByTags() throws Exception {
String[] tagsArray = request().queryString().get("tags");
if (tagsArray == null) {
throw new IllegalArgumentException("'tags' parameter is required");
@@ -104,28 +115,36 @@ public class PetApiController extends Controller {
tags.add(curParam);
}
}
List<Pet> obj = imp.findPetsByTags(tags);
if (configuration.getBoolean("useOutputBeanValidation")) {
for (Pet curItem : obj) {
OpenAPIUtils.validate(curItem);
CompletionStage<List<Pet>> stage = imp.findPetsByTags(tags).thenApply(obj -> {
if (configuration.getBoolean("useOutputBeanValidation")) {
for (Pet curItem : obj) {
OpenAPIUtils.validate(curItem);
}
}
}
JsonNode result = mapper.valueToTree(obj);
return ok(result);
return obj;
});
stage.thenApply(obj -> {
JsonNode result = mapper.valueToTree(obj);
return ok(result);
});
}
@ApiAction
public Result getPetById(Long petId) throws Exception {
Pet obj = imp.getPetById(petId);
if (configuration.getBoolean("useOutputBeanValidation")) {
OpenAPIUtils.validate(obj);
}
JsonNode result = mapper.valueToTree(obj);
return ok(result);
public CompletionStage<Result> getPetById(Long petId) throws Exception {
CompletionStage<Pet> stage = imp.getPetById(petId).thenApply(obj -> {
if (configuration.getBoolean("useOutputBeanValidation")) {
OpenAPIUtils.validate(obj);
}
return obj;
});
stage.thenApply(obj -> {
JsonNode result = mapper.valueToTree(obj);
return ok(result);
});
}
@ApiAction
public Result updatePet() throws Exception {
public CompletionStage<Result> updatePet() throws Exception {
JsonNode nodebody = request().body().asJson();
Pet body;
if (nodebody != null) {
@@ -136,12 +155,14 @@ public class PetApiController extends Controller {
} else {
throw new IllegalArgumentException("'body' parameter is required");
}
imp.updatePet(body);
return ok();
return CompletableFuture.supplyAsync(() -> {
imp.updatePet(body)
return ok();
});
}
@ApiAction
public Result updatePetWithForm(Long petId) throws Exception {
public CompletionStage<Result> updatePetWithForm(Long petId) throws Exception {
String valuename = (request().body().asMultipartFormData().asFormUrlEncoded().get("name"))[0];
String name;
if (valuename != null) {
@@ -156,12 +177,14 @@ public class PetApiController extends Controller {
} else {
status = null;
}
imp.updatePetWithForm(petId, name, status);
return ok();
return CompletableFuture.supplyAsync(() -> {
imp.updatePetWithForm(petId, name, status)
return ok();
});
}
@ApiAction
public Result uploadFile(Long petId) throws Exception {
public CompletionStage<Result> uploadFile(Long petId) throws Exception {
String valueadditionalMetadata = (request().body().asMultipartFormData().asFormUrlEncoded().get("additionalMetadata"))[0];
String additionalMetadata;
if (valueadditionalMetadata != null) {
@@ -170,11 +193,15 @@ public class PetApiController extends Controller {
additionalMetadata = null;
}
Http.MultipartFormData.FilePart file = request().body().asMultipartFormData().getFile("file");
ModelApiResponse obj = imp.uploadFile(petId, additionalMetadata, file);
if (configuration.getBoolean("useOutputBeanValidation")) {
OpenAPIUtils.validate(obj);
}
JsonNode result = mapper.valueToTree(obj);
return ok(result);
CompletionStage<ModelApiResponse> stage = imp.uploadFile(petId, additionalMetadata, file).thenApply(obj -> {
if (configuration.getBoolean("useOutputBeanValidation")) {
OpenAPIUtils.validate(obj);
}
return obj;
});
stage.thenApply(obj -> {
JsonNode result = mapper.valueToTree(obj);
return ok(result);
});
}
}

View File

@@ -23,21 +23,27 @@ public class PetApiControllerImp implements PetApiControllerImpInterface {
}
@Override
public List<Pet> findPetsByStatus( @NotNull List<String> status) throws Exception {
public CompletionStage<List<Pet>> findPetsByStatus( @NotNull List<String> status) throws Exception {
//Do your magic!!!
return new ArrayList<Pet>();
return CompletableFuture.supplyAsync(() -> {
return new ArrayList<Pet>();
});
}
@Override
public List<Pet> findPetsByTags( @NotNull List<String> tags) throws Exception {
public CompletionStage<List<Pet>> findPetsByTags( @NotNull List<String> tags) throws Exception {
//Do your magic!!!
return new ArrayList<Pet>();
return CompletableFuture.supplyAsync(() -> {
return new ArrayList<Pet>();
});
}
@Override
public Pet getPetById(Long petId) throws Exception {
public CompletionStage<Pet> getPetById(Long petId) throws Exception {
//Do your magic!!!
return new Pet();
return CompletableFuture.supplyAsync(() -> {
return new Pet();
});
}
@Override
@@ -51,9 +57,11 @@ public class PetApiControllerImp implements PetApiControllerImpInterface {
}
@Override
public ModelApiResponse uploadFile(Long petId, String additionalMetadata, Http.MultipartFormData.FilePart file) throws Exception {
public CompletionStage<ModelApiResponse> uploadFile(Long petId, String additionalMetadata, Http.MultipartFormData.FilePart file) throws Exception {
//Do your magic!!!
return new ModelApiResponse();
return CompletableFuture.supplyAsync(() -> {
return new ModelApiResponse();
});
}
}

View File

@@ -8,6 +8,8 @@ import play.mvc.Http;
import java.util.List;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.CompletableFuture;
import javax.validation.constraints.*;
@@ -17,16 +19,16 @@ public interface PetApiControllerImpInterface {
void deletePet(Long petId, String apiKey) throws Exception;
List<Pet> findPetsByStatus( @NotNull List<String> status) throws Exception;
CompletionStage<List<Pet>> findPetsByStatus( @NotNull List<String> status) throws Exception;
List<Pet> findPetsByTags( @NotNull List<String> tags) throws Exception;
CompletionStage<List<Pet>> findPetsByTags( @NotNull List<String> tags) throws Exception;
Pet getPetById(Long petId) throws Exception;
CompletionStage<Pet> getPetById(Long petId) throws Exception;
void updatePet(Pet body) throws Exception;
void updatePetWithForm(Long petId, String name, String status) throws Exception;
ModelApiResponse uploadFile(Long petId, String additionalMetadata, Http.MultipartFormData.FilePart file) throws Exception;
CompletionStage<ModelApiResponse> uploadFile(Long petId, String additionalMetadata, Http.MultipartFormData.FilePart file) throws Exception;
}

View File

@@ -16,6 +16,9 @@ import java.io.File;
import openapitools.OpenAPIUtils;
import com.fasterxml.jackson.core.type.TypeReference;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.CompletableFuture;
import javax.validation.constraints.*;
import play.Configuration;
@@ -37,30 +40,40 @@ public class StoreApiController extends Controller {
@ApiAction
public Result deleteOrder(String orderId) throws Exception {
imp.deleteOrder(orderId);
return ok();
public CompletionStage<Result> deleteOrder(String orderId) throws Exception {
return CompletableFuture.supplyAsync(() -> {
imp.deleteOrder(orderId)
return ok();
});
}
@ApiAction
public Result getInventory() throws Exception {
Map<String, Integer> obj = imp.getInventory();
JsonNode result = mapper.valueToTree(obj);
return ok(result);
public CompletionStage<Result> getInventory() throws Exception {
CompletionStage<Map<String, Integer>> stage = imp.getInventory().thenApply(obj -> {
return obj;
});
stage.thenApply(obj -> {
JsonNode result = mapper.valueToTree(obj);
return ok(result);
});
}
@ApiAction
public Result getOrderById( @Min(1) @Max(5)Long orderId) throws Exception {
Order obj = imp.getOrderById(orderId);
if (configuration.getBoolean("useOutputBeanValidation")) {
OpenAPIUtils.validate(obj);
}
JsonNode result = mapper.valueToTree(obj);
return ok(result);
public CompletionStage<Result> getOrderById( @Min(1) @Max(5)Long orderId) throws Exception {
CompletionStage<Order> stage = imp.getOrderById(orderId).thenApply(obj -> {
if (configuration.getBoolean("useOutputBeanValidation")) {
OpenAPIUtils.validate(obj);
}
return obj;
});
stage.thenApply(obj -> {
JsonNode result = mapper.valueToTree(obj);
return ok(result);
});
}
@ApiAction
public Result placeOrder() throws Exception {
public CompletionStage<Result> placeOrder() throws Exception {
JsonNode nodebody = request().body().asJson();
Order body;
if (nodebody != null) {
@@ -71,11 +84,15 @@ public class StoreApiController extends Controller {
} else {
throw new IllegalArgumentException("'body' parameter is required");
}
Order obj = imp.placeOrder(body);
if (configuration.getBoolean("useOutputBeanValidation")) {
OpenAPIUtils.validate(obj);
}
JsonNode result = mapper.valueToTree(obj);
return ok(result);
CompletionStage<Order> stage = imp.placeOrder(body).thenApply(obj -> {
if (configuration.getBoolean("useOutputBeanValidation")) {
OpenAPIUtils.validate(obj);
}
return obj;
});
stage.thenApply(obj -> {
JsonNode result = mapper.valueToTree(obj);
return ok(result);
});
}
}

View File

@@ -17,21 +17,27 @@ public class StoreApiControllerImp implements StoreApiControllerImpInterface {
}
@Override
public Map<String, Integer> getInventory() throws Exception {
public CompletionStage<Map<String, Integer>> getInventory() throws Exception {
//Do your magic!!!
return new HashMap<String, Integer>();
return CompletableFuture.supplyAsync(() -> {
return new HashMap<String, Integer>();
});
}
@Override
public Order getOrderById( @Min(1) @Max(5)Long orderId) throws Exception {
public CompletionStage<Order> getOrderById( @Min(1) @Max(5)Long orderId) throws Exception {
//Do your magic!!!
return new Order();
return CompletableFuture.supplyAsync(() -> {
return new Order();
});
}
@Override
public Order placeOrder(Order body) throws Exception {
public CompletionStage<Order> placeOrder(Order body) throws Exception {
//Do your magic!!!
return new Order();
return CompletableFuture.supplyAsync(() -> {
return new Order();
});
}
}

View File

@@ -7,6 +7,8 @@ import play.mvc.Http;
import java.util.List;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.CompletableFuture;
import javax.validation.constraints.*;
@@ -14,10 +16,10 @@ import javax.validation.constraints.*;
public interface StoreApiControllerImpInterface {
void deleteOrder(String orderId) throws Exception;
Map<String, Integer> getInventory() throws Exception;
CompletionStage<Map<String, Integer>> getInventory() throws Exception;
Order getOrderById( @Min(1) @Max(5)Long orderId) throws Exception;
CompletionStage<Order> getOrderById( @Min(1) @Max(5)Long orderId) throws Exception;
Order placeOrder(Order body) throws Exception;
CompletionStage<Order> placeOrder(Order body) throws Exception;
}

View File

@@ -16,6 +16,9 @@ import java.io.File;
import openapitools.OpenAPIUtils;
import com.fasterxml.jackson.core.type.TypeReference;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.CompletableFuture;
import javax.validation.constraints.*;
import play.Configuration;
@@ -37,7 +40,7 @@ public class UserApiController extends Controller {
@ApiAction
public Result createUser() throws Exception {
public CompletionStage<Result> createUser() throws Exception {
JsonNode nodebody = request().body().asJson();
User body;
if (nodebody != null) {
@@ -48,12 +51,14 @@ public class UserApiController extends Controller {
} else {
throw new IllegalArgumentException("'body' parameter is required");
}
imp.createUser(body);
return ok();
return CompletableFuture.supplyAsync(() -> {
imp.createUser(body)
return ok();
});
}
@ApiAction
public Result createUsersWithArrayInput() throws Exception {
public CompletionStage<Result> createUsersWithArrayInput() throws Exception {
JsonNode nodebody = request().body().asJson();
List<User> body;
if (nodebody != null) {
@@ -66,12 +71,14 @@ public class UserApiController extends Controller {
} else {
throw new IllegalArgumentException("'body' parameter is required");
}
imp.createUsersWithArrayInput(body);
return ok();
return CompletableFuture.supplyAsync(() -> {
imp.createUsersWithArrayInput(body)
return ok();
});
}
@ApiAction
public Result createUsersWithListInput() throws Exception {
public CompletionStage<Result> createUsersWithListInput() throws Exception {
JsonNode nodebody = request().body().asJson();
List<User> body;
if (nodebody != null) {
@@ -84,28 +91,36 @@ public class UserApiController extends Controller {
} else {
throw new IllegalArgumentException("'body' parameter is required");
}
imp.createUsersWithListInput(body);
return ok();
return CompletableFuture.supplyAsync(() -> {
imp.createUsersWithListInput(body)
return ok();
});
}
@ApiAction
public Result deleteUser(String username) throws Exception {
imp.deleteUser(username);
return ok();
public CompletionStage<Result> deleteUser(String username) throws Exception {
return CompletableFuture.supplyAsync(() -> {
imp.deleteUser(username)
return ok();
});
}
@ApiAction
public Result getUserByName(String username) throws Exception {
User obj = imp.getUserByName(username);
if (configuration.getBoolean("useOutputBeanValidation")) {
OpenAPIUtils.validate(obj);
}
JsonNode result = mapper.valueToTree(obj);
return ok(result);
public CompletionStage<Result> getUserByName(String username) throws Exception {
CompletionStage<User> stage = imp.getUserByName(username).thenApply(obj -> {
if (configuration.getBoolean("useOutputBeanValidation")) {
OpenAPIUtils.validate(obj);
}
return obj;
});
stage.thenApply(obj -> {
JsonNode result = mapper.valueToTree(obj);
return ok(result);
});
}
@ApiAction
public Result loginUser() throws Exception {
public CompletionStage<Result> loginUser() throws Exception {
String valueusername = request().getQueryString("username");
String username;
if (valueusername != null) {
@@ -120,19 +135,25 @@ public class UserApiController extends Controller {
} else {
throw new IllegalArgumentException("'password' parameter is required");
}
String obj = imp.loginUser(username, password);
JsonNode result = mapper.valueToTree(obj);
return ok(result);
CompletionStage<String> stage = imp.loginUser(username, password).thenApply(obj -> {
return obj;
});
stage.thenApply(obj -> {
JsonNode result = mapper.valueToTree(obj);
return ok(result);
});
}
@ApiAction
public Result logoutUser() throws Exception {
imp.logoutUser();
return ok();
public CompletionStage<Result> logoutUser() throws Exception {
return CompletableFuture.supplyAsync(() -> {
imp.logoutUser()
return ok();
});
}
@ApiAction
public Result updateUser(String username) throws Exception {
public CompletionStage<Result> updateUser(String username) throws Exception {
JsonNode nodebody = request().body().asJson();
User body;
if (nodebody != null) {
@@ -143,7 +164,9 @@ public class UserApiController extends Controller {
} else {
throw new IllegalArgumentException("'body' parameter is required");
}
imp.updateUser(username, body);
return ok();
return CompletableFuture.supplyAsync(() -> {
imp.updateUser(username, body)
return ok();
});
}
}

View File

@@ -32,15 +32,19 @@ public class UserApiControllerImp implements UserApiControllerImpInterface {
}
@Override
public User getUserByName(String username) throws Exception {
public CompletionStage<User> getUserByName(String username) throws Exception {
//Do your magic!!!
return new User();
return CompletableFuture.supplyAsync(() -> {
return new User();
});
}
@Override
public String loginUser( @NotNull String username, @NotNull String password) throws Exception {
public CompletionStage<String> loginUser( @NotNull String username, @NotNull String password) throws Exception {
//Do your magic!!!
return new String();
return CompletableFuture.supplyAsync(() -> {
return new String();
});
}
@Override

View File

@@ -7,6 +7,8 @@ import play.mvc.Http;
import java.util.List;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.CompletableFuture;
import javax.validation.constraints.*;
@@ -20,9 +22,9 @@ public interface UserApiControllerImpInterface {
void deleteUser(String username) throws Exception;
User getUserByName(String username) throws Exception;
CompletionStage<User> getUserByName(String username) throws Exception;
String loginUser( @NotNull String username, @NotNull String password) throws Exception;
CompletionStage<String> loginUser( @NotNull String username, @NotNull String password) throws Exception;
void logoutUser() throws Exception;