Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion docs/asciidoc/modules/openapi.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,14 @@ To avoid this behaviour you can specify maven build phase which suits your needs
|`openapi.yaml`
|Set openAPI template file path.

|===
|`copyOpenApiSpecTo`
|
|Copy the generated OpenAPI spec to the given file in the project repository. The format is
determined by the file extension: `.yaml`, `.yml` or `.json`. Example:

<copyOpenApiSpecTo>${project.basedir}/docs/openapi.yaml</copyOpenApiSpecTo>

|`===

=== Usage

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,14 @@
import static org.apache.maven.plugins.annotations.ResolutionScope.COMPILE_PLUS_RUNTIME;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;

Expand Down Expand Up @@ -53,6 +58,9 @@ public class OpenAPIMojo extends BaseMojo {

@Parameter private List<File> adoc;

@Parameter(property = "openAPI.copyOpenApiSpecTo")
private File copyOpenApiSpecTo;

@Override
protected void doExecute(List<MavenProject> projects, String mainClass) throws Exception {
ClassLoader classLoader = createClassLoader(projects);
Expand Down Expand Up @@ -84,10 +92,48 @@ protected void doExecute(List<MavenProject> projects, String mainClass) throws E
var result = tool.generate(mainClass);

var adocPath = ofNullable(adoc).orElse(List.of()).stream().map(File::toPath).toList();
var written = new ArrayList<Path>();
for (var format : OpenAPIGenerator.Format.values()) {
tool.export(result, format, Map.of("adoc", adocPath))
.forEach(output -> getLog().info(" writing: " + output));
written.addAll(tool.export(result, format, Map.of("adoc", adocPath)));
}
written.forEach(output -> getLog().info(" writing: " + output));

if (copyOpenApiSpecTo != null) {
var destination = copyOpenApiSpecTo.toPath();
copySpec(written, destination);
getLog().info(" copying: " + destination);
}
}

public static void copySpec(List<Path> written, Path destination) throws IOException {
var format = specFormat(destination);
var source =
written.stream()
.filter(path -> path.getFileName().toString().endsWith("." + format.extension()))
.findFirst()
.orElseThrow(
() ->
new IOException(
String.format(
"OpenAPI %s output not found for copyOpenApiSpecTo: %s",
format.name(), destination)));
var parent = destination.getParent();
if (parent != null) {
Files.createDirectories(parent);
}
Files.copy(source, destination, StandardCopyOption.REPLACE_EXISTING);
}

public static OpenAPIGenerator.Format specFormat(Path destination) {
var name = destination.getFileName().toString().toLowerCase(Locale.ROOT);
if (name.endsWith(".json")) {
return OpenAPIGenerator.Format.JSON;
}
if (name.endsWith(".yaml") || name.endsWith(".yml")) {
return OpenAPIGenerator.Format.YAML;
}
throw new IllegalArgumentException(
"copyOpenApiSpecTo must end with .yaml, .yml or .json: " + destination);
}

private Optional<String> trim(String value) {
Expand Down Expand Up @@ -186,4 +232,30 @@ public void setJavadoc(String javadoc) {
public String getJavadoc() {
return javadoc;
}

/**
* Copy the generated OpenAPI spec to the given file. The format is determined by the file
* extension: <code>.yaml</code>, <code>.yml</code> or <code>.json</code>.
*
* @return Destination file.
*/
public @Nullable File getCopyOpenApiSpecTo() {
return copyOpenApiSpecTo;
}

/**
* Copy the generated OpenAPI spec to the given file. The format is determined by the file
* extension: <code>.yaml</code>, <code>.yml</code> or <code>.json</code>.
*
* <p>Example:
*
* <pre>{@code
* <copyOpenApiSpecTo>${project.basedir}/docs/openapi.yaml</copyOpenApiSpecTo>
* }</pre>
*
* @param copyOpenApiSpecTo Destination file.
*/
public void setCopyOpenApiSpecTo(@Nullable File copyOpenApiSpecTo) {
this.copyOpenApiSpecTo = copyOpenApiSpecTo;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package io.jooby.maven;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;

import io.jooby.openapi.OpenAPIGenerator;

public class OpenAPIMojoTest {

@Test
public void specFormat() {
assertEquals(
OpenAPIGenerator.Format.YAML, OpenAPIMojo.specFormat(Path.of("docs/openapi.yaml")));
assertEquals(
OpenAPIGenerator.Format.YAML, OpenAPIMojo.specFormat(Path.of("docs/openapi.yml")));
assertEquals(
OpenAPIGenerator.Format.JSON, OpenAPIMojo.specFormat(Path.of("docs/openapi.json")));
assertThrows(
IllegalArgumentException.class, () -> OpenAPIMojo.specFormat(Path.of("docs/openapi.txt")));
}

@Test
public void copyYamlSpec(@TempDir Path tempDir) throws Exception {
var outputDir = tempDir.resolve("classes/myapp");
Files.createDirectories(outputDir);
var source = outputDir.resolve("App.yaml");
Files.writeString(source, "openapi: 3.0.1");

var destination = tempDir.resolve("docs/openapi.yml");
OpenAPIMojo.copySpec(List.of(source), destination);

assertTrue(Files.isRegularFile(destination));
assertEquals(Files.readString(source), Files.readString(destination));
}

@Test
public void copyJsonSpec(@TempDir Path tempDir) throws Exception {
var outputDir = tempDir.resolve("classes/myapp");
Files.createDirectories(outputDir);
var source = outputDir.resolve("App.json");
Files.writeString(source, "{\"openapi\":\"3.0.1\"}");

var destination = tempDir.resolve("docs/openapi.json");
OpenAPIMojo.copySpec(List.of(source), destination);

assertTrue(Files.isRegularFile(destination));
assertEquals(Files.readString(source), Files.readString(destination));
}
}
Loading