asciidoc markup generator (#3845)

* basic asciidoc markup generation

* asciidoc markup include processing with mustache filter

* asciidoc tests, separate include filters

* asciidoc petstore sample

* add asciidoc generator to readme

* test asciidoc generator for all include files with own json spec.

* link fillter to link generated test data into asciidoc markup

* fix and cleanup names asciidoc tests.

* fix travis build error, removed windows line endings from mustache asciiidoc templates.

* asciidoc generator: comment and reduce visibility of helper method (fix dron build)

* asciidoc: windows linefeed again (fix travis ci)

* asciidoc generator: remove \t and format again.

* fix ascidoc generator ci builds ... ongoing..

* asciidoc: add generator .md files, unix line ending.
This commit is contained in:
Man 2019-09-14 12:39:58 +02:00 committed by William Cheng
parent ec5df2e1c0
commit 8055231400
29 changed files with 2554 additions and 1 deletions

View File

@ -67,7 +67,7 @@ OpenAPI Generator allows generation of API client libraries (SDK generation), se
|-|-|
**API clients** | **ActionScript**, **Ada**, **Apex**, **Bash**, **C**, **C#** (.net 2.0, 3.5 or later, .NET Standard 1.3 - 2.0, .NET Core 2.0), **C++** (cpp-restsdk, Qt5, Tizen), **Clojure**, **Dart (1.x, 2.x)**, **Elixir**, **Elm**, **Eiffel**, **Erlang**, **Go**, **Groovy**, **Haskell** (http-client, Servant), **Java** (Jersey1.x, Jersey2.x, OkHttp, Retrofit1.x, Retrofit2.x, Feign, RestTemplate, RESTEasy, Vertx, Google API Client Library for Java, Rest-assured, Spring 5 Web Client), **Kotlin**, **Lua**, **Nim**, **Node.js/JavaScript** (ES5, ES6, AngularJS with Google Closure Compiler annotations, Flow types), **Objective-C**, **OCaml**, **Perl**, **PHP**, **PowerShell**, **Python**, **R**, **Ruby**, **Rust** (rust, rust-server), **Scala** (akka, http4s, scalaz, swagger-async-httpclient), **Swift** (2.x, 3.x, 4.x), **Typescript** (AngularJS, Angular (2.x - 8.x), Aurelia, Axios, Fetch, Inversify, jQuery, Node, Rxjs)
**Server stubs** | **Ada**, **C#** (ASP.NET Core, NancyFx), **C++** (Pistache, Restbed, Qt5 QHTTPEngine), **Erlang**, **F#** (Giraffe), **Go** (net/http, Gin), **Haskell** (Servant), **Java** (MSF4J, Spring, Undertow, JAX-RS: CDI, CXF, Inflector, Jersey, RestEasy, Play Framework, [PKMST](https://github.com/ProKarma-Inc/pkmst-getting-started-examples)), **Kotlin** (Spring Boot, Ktor), **PHP** (Laravel, Lumen, Slim, Silex, [Symfony](https://symfony.com/), [Zend Expressive](https://github.com/zendframework/zend-expressive)), **Python** (Flask), **NodeJS**, **Ruby** (Sinatra, Rails5), **Rust** (rust-server), **Scala** ([Finch](https://github.com/finagle/finch), [Lagom](https://github.com/lagom/lagom), [Play](https://www.playframework.com/), Scalatra)
**API documentation generators** | **HTML**, **Confluence Wiki**
**API documentation generators** | **HTML**, **Confluence Wiki**, **Asciidoc**
**Configuration files** | [**Apache2**](https://httpd.apache.org/)
**Others** | **GraphQL**, **JMeter**, **MySQL Schema**, **Protocol Buffer**

View File

@ -0,0 +1,31 @@
#!/bin/sh
SCRIPT="$0"
while [ -h "$SCRIPT" ] ; do
ls=$(ls -ld "$SCRIPT")
link=$(expr "$ls" : '.*-> \(.*\)$')
if expr "$link" : '/.*' > /dev/null; then
SCRIPT="$link"
else
SCRIPT=$(dirname "$SCRIPT")/"$link"
fi
done
if [ ! -d "${APP_DIR}" ]; then
APP_DIR=$(dirname "$SCRIPT")/..
APP_DIR=$(cd "${APP_DIR}"; pwd)
fi
executable="./modules/openapi-generator-cli/target/openapi-generator-cli.jar"
if [ ! -f "$executable" ]
then
mvn clean package
fi
# if you've executed sbt assembly previously it will use that instead.
export JAVA_OPTS="${JAVA_OPTS} -Xmx1024M -DloggerPath=conf/log4j.properties"
ags="$@ generate -t modules/openapi-generator/src/main/resources/asciidoc-documentation --additional-properties=specDir=modules/openapi-generator/src/main/resources/asciidoc-documentation,snippetDir=. -i modules/openapi-generator/src/test/resources/2_0/petstore.yaml -g asciidoc -o samples/documentation/asciidoc"
java ${JAVA_OPTS} -jar ${executable} ${ags}

View File

@ -0,0 +1,10 @@
set executable=.\modules\openapi-generator-cli\target\openapi-generator-cli.jar
If Not Exist %executable% (
mvn clean package
)
REM set JAVA_OPTS=%JAVA_OPTS% -Xmx1024M -DloggerPath=conf/log4j.properties
set ags=generate --artifact-id "asciidoc-petstore-documentation" -t modules\openapi-generator\src\main\resources\asciidoc-documentation --additional-properties=specDir=modules\openapi-generator\src\main\resources\asciidoc-documentation,snippetDir=. -i modules\openapi-generator\src\test\resources\2_0\petstore.yaml -g asciidoc -o samples\documentation\asciidoc
java %JAVA_OPTS% -jar %executable% %ags%

View File

@ -117,6 +117,7 @@ The following generators are available:
## DOCUMENTATION generators
* [asciidoc](generators/asciidoc)
* [cwiki](generators/cwiki)
* [dynamic-html](generators/dynamic-html)
* [html](generators/html)

View File

@ -0,0 +1,25 @@
---
id: generator-opts-documentation-asciidoc
title: Config Options for asciidoc
sidebar_label: asciidoc
---
| Option | Description | Values | Default |
| ------ | ----------- | ------ | ------- |
|sortParamsByRequiredFlag|Sort method arguments to place required parameters before optional parameters.| |true|
|ensureUniqueParams|Whether to ensure parameter names are unique in an operation (rename parameters that are not).| |true|
|allowUnicodeIdentifiers|boolean, toggles whether unicode identifiers are allowed in names or not, default is false| |false|
|prependFormOrBodyParameters|Add form or body parameters to the beginning of the parameter list.| |false|
|appName|short name of the application| |null|
|appDescription|description of the application| |null|
|infoUrl|a URL where users can get more information about the application| |null|
|infoEmail|an email address to contact for inquiries about the application| |null|
|licenseInfo|a short description of the license| |null|
|licenseUrl|a URL pointing to the full license| |null|
|invokerPackage|root package for generated code| |null|
|groupId|groupId in generated pom.xml| |null|
|artifactId|artifactId in generated pom.xml. This also becomes part of the generated library's filename| |null|
|artifactVersion|artifact version in generated pom.xml. This also becomes part of the generated library's filename| |null|
|snippetDir|path with includable markup snippets (e.g. test output generated by restdoc, default: .| |.|
|specDir|path with includable markup spec files (e.g. handwritten additional docs, default: .| |..|

View File

@ -0,0 +1,260 @@
package org.openapitools.codegen.languages;
import org.openapitools.codegen.*;
import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.HashSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.samskivert.mustache.Mustache;
import com.samskivert.mustache.Template;
import io.swagger.v3.oas.models.OpenAPI;
/**
* basic asciidoc markup generator.
*
* @see <a href="https://asciidoctor.org">asciidoctor</a>
*/
public class AsciidocDocumentationCodegen extends DefaultCodegen implements CodegenConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(AsciidocDocumentationCodegen.class);
public static final String SPEC_DIR = "specDir";
public static final String SNIPPET_DIR = "snippetDir";
/**
* Lambda emitting an asciidoc "include::filename.adoc[]" if file is found in
* path. Use:
*
* <pre>
* {{#includemarkup}}{{name}}/description.adoc{{/includemarkup}}
* </pre>
*/
public class IncludeMarkupLambda implements Mustache.Lambda {
private long includeCount = 0;
private long notFoundCount = 0;
private String basePath;
public IncludeMarkupLambda(final String basePath) {
this.basePath = basePath;
}
public String resetCounter() {
String msg = "included: " + includeCount + " notFound: " + notFoundCount + " from " + basePath;
includeCount = 0;
notFoundCount = 0;
return msg;
}
@Override
public void execute(final Template.Fragment frag, final Writer out) throws IOException {
final String relativeFileName = AsciidocDocumentationCodegen.sanitize(frag.execute());
final Path filePathToInclude = Paths.get(basePath, relativeFileName).toAbsolutePath();
if (Files.isRegularFile(filePathToInclude)) {
LOGGER.debug(
"including " + ++includeCount + ". file into markup from: " + filePathToInclude.toString());
out.write("\ninclude::" + relativeFileName + "[]\n");
} else {
LOGGER.debug(++notFoundCount + ". file not found, skip include for: " + filePathToInclude.toString());
out.write("\n// markup not found, no include ::" + relativeFileName + "[]\n");
}
}
}
/**
* Lambda emitting an asciidoc "http link" if file is found in path. Use:
*
* <pre>
* {{#snippetLink}}markup until koma, /{{name}}.json{{/snippetLink}}
* </pre>
*/
public class LinkMarkupLambda implements Mustache.Lambda {
private long linkedCount = 0;
private long notFoundLinkCount = 0;
private String basePath;
public LinkMarkupLambda(final String basePath) {
this.basePath = basePath;
}
public String resetCounter() {
String msg = "linked:" + linkedCount + " notFound: " + notFoundLinkCount + " from " + basePath;
linkedCount = 0;
notFoundLinkCount = 0;
return msg;
}
@Override
public void execute(final Template.Fragment frag, final Writer out) throws IOException {
final String content = frag.execute();
final String[] tokens = content.split(",", 2);
final String linkName = tokens.length > 0 ? tokens[0] : "";
final String relativeFileName = AsciidocDocumentationCodegen
.sanitize(tokens.length > 1 ? tokens[1] : linkName);
final Path filePathToLinkTo = Paths.get(basePath, relativeFileName).toAbsolutePath();
if (Files.isRegularFile(filePathToLinkTo)) {
LOGGER.debug("linking " + ++linkedCount + ". file into markup from: " + filePathToLinkTo.toString());
out.write("\n" + linkName + " link:" + relativeFileName + "[]\n");
} else {
LOGGER.debug(++notFoundLinkCount + ". file not found, skip link for: " + filePathToLinkTo.toString());
out.write("\n// file not found, no " + linkName + " link :" + relativeFileName + "[]\n");
}
}
}
protected String invokerPackage = "org.openapitools.client";
protected String groupId = "org.openapitools";
protected String artifactId = "openapi-client";
protected String artifactVersion = "1.0.0";
private IncludeMarkupLambda includeSpecMarkupLambda;
private IncludeMarkupLambda includeSnippetMarkupLambda;
private LinkMarkupLambda linkSnippetMarkupLambda;
public CodegenType getTag() {
return CodegenType.DOCUMENTATION;
}
/**
* extracted filter value should be relative to be of use as link or include
* file.
*
* @param name filename to sanitize
* @return trimmed and striped path part or empty string.
*/
static String sanitize(final String name) {
String sanitized = name == null ? "" : name.trim();
return sanitized.startsWith(File.separator) || sanitized.startsWith("/") ? sanitized.substring(1) : sanitized;
}
public String getName() {
return "asciidoc";
}
public String getHelp() {
return "Generates asciidoc markup based documentation.";
}
public String getSpecDir() {
return additionalProperties.get("specDir").toString();
}
public String getSnippetDir() {
return additionalProperties.get("snippetDir").toString();
}
public AsciidocDocumentationCodegen() {
super();
LOGGER.trace("start asciidoc codegen");
outputFolder = "generated-code" + File.separator + "asciidoc";
embeddedTemplateDir = templateDir = "asciidoc-documentation";
defaultIncludes = new HashSet<String>();
cliOptions.add(new CliOption("appName", "short name of the application"));
cliOptions.add(new CliOption("appDescription", "description of the application"));
cliOptions.add(new CliOption("infoUrl", "a URL where users can get more information about the application"));
cliOptions.add(new CliOption("infoEmail", "an email address to contact for inquiries about the application"));
cliOptions.add(new CliOption("licenseInfo", "a short description of the license"));
cliOptions.add(new CliOption(CodegenConstants.LICENSE_URL, "a URL pointing to the full license"));
cliOptions.add(new CliOption(CodegenConstants.INVOKER_PACKAGE, CodegenConstants.INVOKER_PACKAGE_DESC));
cliOptions.add(new CliOption(CodegenConstants.GROUP_ID, CodegenConstants.GROUP_ID_DESC));
cliOptions.add(new CliOption(CodegenConstants.ARTIFACT_ID, CodegenConstants.ARTIFACT_ID_DESC));
cliOptions.add(new CliOption(CodegenConstants.ARTIFACT_VERSION, CodegenConstants.ARTIFACT_VERSION_DESC));
cliOptions.add(new CliOption(SNIPPET_DIR,
"path with includable markup snippets (e.g. test output generated by restdoc, default: .")
.defaultValue("."));
cliOptions.add(new CliOption(SPEC_DIR,
"path with includable markup spec files (e.g. handwritten additional docs, default: .")
.defaultValue(".."));
additionalProperties.put("appName", "OpenAPI Sample description");
additionalProperties.put("appDescription", "A sample OpenAPI documentation");
additionalProperties.put("infoUrl", "https://openapi-generator.tech");
additionalProperties.put("infoEmail", "team@openapitools.org");
additionalProperties.put("licenseInfo", "All rights reserved");
additionalProperties.put(CodegenConstants.LICENSE_URL, "http://apache.org/licenses/LICENSE-2.0.html");
additionalProperties.put(CodegenConstants.INVOKER_PACKAGE, invokerPackage);
additionalProperties.put(CodegenConstants.GROUP_ID, groupId);
additionalProperties.put(CodegenConstants.ARTIFACT_ID, artifactId);
additionalProperties.put(CodegenConstants.ARTIFACT_VERSION, artifactVersion);
supportingFiles.add(new SupportingFile("index.mustache", "", "index.adoc"));
reservedWords = new HashSet<String>();
languageSpecificPrimitives = new HashSet<String>();
importMapping = new HashMap<String, String>();
}
@Override
public String escapeQuotationMark(String input) {
return input; // just return the original string
}
@Override
public String escapeUnsafeCharacters(String input) {
return input; // just return the original string
}
@Override
public void processOpts() {
super.processOpts();
String specDir = this.additionalProperties.get(SPEC_DIR) + "";
if (!Files.isDirectory(Paths.get(specDir))) {
LOGGER.warn("base part for include markup lambda not found: " + specDir + " as "
+ Paths.get(specDir).toAbsolutePath());
}
;
this.includeSpecMarkupLambda = new IncludeMarkupLambda(specDir);
additionalProperties.put("specinclude", this.includeSpecMarkupLambda);
String snippetDir = this.additionalProperties.get(SNIPPET_DIR) + "";
if (!Files.isDirectory(Paths.get(snippetDir))) {
LOGGER.warn("base part for include markup lambda not found: " + snippetDir + " as "
+ Paths.get(snippetDir).toAbsolutePath());
}
;
this.includeSnippetMarkupLambda = new IncludeMarkupLambda(snippetDir);
additionalProperties.put("snippetinclude", this.includeSnippetMarkupLambda);
this.linkSnippetMarkupLambda = new LinkMarkupLambda(snippetDir);
additionalProperties.put("snippetlink", this.linkSnippetMarkupLambda);
}
@Override
public void processOpenAPI(OpenAPI openAPI) {
if (this.includeSpecMarkupLambda != null) {
LOGGER.info("specs: " + ": " + this.includeSpecMarkupLambda.resetCounter());
}
if (this.includeSnippetMarkupLambda != null) {
LOGGER.info("snippets: " + ": " + this.includeSnippetMarkupLambda.resetCounter());
}
super.processOpenAPI(openAPI);
}
}

View File

@ -114,3 +114,5 @@ org.openapitools.codegen.languages.TypeScriptJqueryClientCodegen
org.openapitools.codegen.languages.TypeScriptNodeClientCodegen
org.openapitools.codegen.languages.TypeScriptRxjsClientCodegen
org.openapitools.codegen.languages.FsharpGiraffeServerCodegen
org.openapitools.codegen.languages.AsciidocDocumentationCodegen

View File

@ -0,0 +1,101 @@
= {{{appName}}}
{{infoEmail}}
{{#version}}{{{version}}}{{/version}}
:toc: left
:numbered:
:toclevels: 3
:source-highlighter: highlightjs
:keywords: openapi, rest, {{appName}}
:specDir: {{specDir}}
:snippetDir: {{snippetDir}}
:generator-template: v1 2019-09-03
:info-url: {{infoUrl}}
:app-name: {{appName}}
[abstract]
.Abstract
{{{appDescription}}}
{{#specinclude}}intro.adoc{{/specinclude}}
== Endpoints
{{#apiInfo}}
{{#apis}}
{{#operations}}
[.{{baseName}}]
=== {{baseName}}
{{#operation}}
[.{{nickname}}]
==== {{nickname}}
`{{httpMethod}} {{path}}`
{{{summary}}}
===== Description
{{{notes}}}
{{#specinclude}}{{path}}/{{httpMethod}}/spec.adoc{{/specinclude}}
{{> params}}
===== Return Type
{{#hasReference}}
{{^returnSimpleType}}{{returnContainer}}[{{/returnSimpleType}}<<{{returnBaseType}}>>{{^returnSimpleType}}]{{/returnSimpleType}}
{{/hasReference}}
{{^hasReference}}
{{#returnType}}<<{{returnType}}>>{{/returnType}}
{{^returnType}}-{{/returnType}}
{{/hasReference}}
{{#hasProduces}}
===== Content Type
{{#produces}}
* {{{mediaType}}}
{{/produces}}
{{/hasProduces}}
===== Responses
.http response codes
[cols="2,3,1"]
|===
| Code | Message | Datatype
{{#responses}}
| {{code}}
| {{message}}
| {{^simpleType}}{{dataType}}[<<{{baseType}}>>]{{/simpleType}} {{#simpleType}}<<{{dataType}}>>{{/simpleType}}
{{/responses}}
|===
===== Samples
{{#snippetinclude}}{{path}}/{{httpMethod}}/http-request.adoc{{/snippetinclude}}
{{#snippetinclude}}{{path}}/{{httpMethod}}/http-response.adoc{{/snippetinclude}}
{{#snippetlink}}* wiremock data, {{path}}/{{httpMethod}}/{{httpMethod}}.json{{/snippetlink}}
ifdef::internal-generation[]
===== Implementation
{{#specinclude}}{{path}}/{{httpMethod}}/implementation.adoc{{/specinclude}}
endif::internal-generation[]
{{/operation}}
{{/operations}}
{{/apis}}
{{/apiInfo}}
{{> model}}

View File

@ -0,0 +1,28 @@
[#models]
== Models
{{#models}}
{{#model}}
[#{{classname}}]
==== _{{classname}}_ {{title}}
{{unescapedDescription}}
[.fields-{{classname}}]
[cols="2,1,2,4,1"]
|===
| Field Name| Required| Type| Description| Format
{{#vars}}
| {{name}}
| {{#required}}X{{/required}}
| {{dataType}} {{#isContainer}} of <<{{complexType}}>>{{/isContainer}}
| {{description}}
| {{{dataFormat}}} {{#isEnum}}Enum: _ {{#_enum}}{{this}}, {{/_enum}}{{/isEnum}} _
{{/vars}}
|===
{{/model}}
{{/models}}

View File

@ -0,0 +1,5 @@
| {{paramName}}
| {{description}} {{#baseType}}<<{{baseType}}>>{{/baseType}}
| {{^required}}-{{/required}}{{#required}}X{{/required}}
| {{defaultValue}}
| {{{pattern}}}

View File

@ -0,0 +1,53 @@
===== Parameters
{{#hasPathParams}}
====== Path Parameters
[cols="2,3,1,1,1"]
|===
|Name| Description| Required| Default| Pattern
{{#pathParams}}
{{>param}}
{{/pathParams}}
|===
{{/hasPathParams}}
{{#hasBodyParam}}
===== Body Parameter
[cols="2,3,1,1,1"]
|===
|Name| Description| Required| Default| Pattern
{{#bodyParams}}
{{>param}}
{{/bodyParams}}
|===
{{/hasBodyParam}}
{{#hasHeaderParams}}
====== Header Parameters
[cols="2,3,1,1,1"]
|===
|Name| Description| Required| Default| Pattern
{{#headerParams}}
{{>param}}
{{/headerParams}}
|===
{{/hasHeaderParams}}
{{#hasQueryParams}}
====== Query Parameters
[cols="2,3,1,1,1"]
|===
|Name| Description| Required| Default| Pattern
{{#queryParams}}
{{>param}}
{{/queryParams}}
|===
{{/hasQueryParams}}

View File

@ -0,0 +1 @@
// openapi generator built documentation, see https://github.com/OpenAPITools/openapi-generator

View File

@ -0,0 +1,117 @@
package org.openapitools.codegen.asciidoc;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import org.apache.commons.io.FileUtils;
import org.openapitools.codegen.ClientOptInput;
import org.openapitools.codegen.CodegenConfig;
import org.openapitools.codegen.DefaultGenerator;
import org.openapitools.codegen.MockDefaultGenerator;
import org.openapitools.codegen.TestUtils;
import org.openapitools.codegen.config.CodegenConfigurator;
import org.openapitools.codegen.languages.AsciidocDocumentationCodegen;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.Assert;
import org.testng.annotations.Test;
import io.swagger.v3.oas.models.OpenAPI;
/** check against ping.yaml spec. */
public class AsciidocGeneratorTest {
private static final Logger LOGGER = LoggerFactory.getLogger(AsciidocGeneratorTest.class);
@Test
public void testPingSpecTitle() throws Exception {
final OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/ping.yaml");
AsciidocDocumentationCodegen codeGen = new AsciidocDocumentationCodegen();
codeGen.preprocessOpenAPI(openAPI);
Assert.assertEquals(openAPI.getInfo().getTitle(), "ping test");
}
@Test
public void testGenerateIndexAsciidocMarkupFileWithAsciidocGenerator() throws Exception {
File output = Files.createTempDirectory("test").toFile();
final CodegenConfigurator configurator = new CodegenConfigurator().setGeneratorName("asciidoc")
.setInputSpec("src/test/resources/3_0/ping.yaml").setOutputDir(output.getAbsolutePath())
.addAdditionalProperty(AsciidocDocumentationCodegen.SNIPPET_DIR, "MY-SNIPPET-DIR")
.addAdditionalProperty(AsciidocDocumentationCodegen.SPEC_DIR, "MY-SPEC-DIR");
final ClientOptInput clientOptInput = configurator.toClientOptInput();
MockDefaultGenerator generator = new MockDefaultGenerator();
generator.opts(clientOptInput).generate();
Map<String, String> generatedFiles = generator.getFiles();
TestUtils.ensureContainsFile(generatedFiles, output, "index.adoc");
}
@Test
public void testGenerateIndexAsciidocMarkupContent() throws Exception {
final File output = Files.createTempDirectory("test").toFile();
output.mkdirs();
output.deleteOnExit();
final OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/ping.yaml");
CodegenConfig codegenConfig = new AsciidocDocumentationCodegen();
codegenConfig.setOutputDir(output.getAbsolutePath());
ClientOptInput clientOptInput = new ClientOptInput().openAPI(openAPI).config(codegenConfig);
DefaultGenerator generator = new DefaultGenerator();
List<File> files = generator.opts(clientOptInput).generate();
boolean markupFileGenerated = false;
for (File file : files) {
if (file.getName().equals("index.adoc")) {
markupFileGenerated = true;
String markupContent = FileUtils.readFileToString(file, StandardCharsets.UTF_8);
// check on some basic asciidoc markup content
Assert.assertTrue(markupContent.contains("= ping test"),
"expected = header in: " + markupContent.substring(0, 50));
Assert.assertTrue(markupContent.contains(":toc: "),
"expected = :toc: " + markupContent.substring(0, 50));
}
}
Assert.assertTrue(markupFileGenerated, "Default api file is not generated!");
}
@Test
public void testAdditionalDirectoriesGeneratedIntoHeaderAttributes() throws Exception {
File output = Files.createTempDirectory("test").toFile();
LOGGER.info("test: generating sample markup " + output.getAbsolutePath());
Map<String, Object> props = new TreeMap<String, Object>();
props.put("specDir", "spec");
final CodegenConfigurator configurator = new CodegenConfigurator().setGeneratorName("asciidoc")
.setInputSpec("src/test/resources/3_0/ping.yaml").setOutputDir(output.getAbsolutePath())
.addAdditionalProperty(AsciidocDocumentationCodegen.SPEC_DIR, "SPEC-DIR")
.addAdditionalProperty(AsciidocDocumentationCodegen.SNIPPET_DIR, "MY/SNIPPET/DIR");
DefaultGenerator generator = new DefaultGenerator();
List<File> files = generator.opts(configurator.toClientOptInput()).generate();
boolean markupFileGenerated = false;
for (File file : files) {
if (file.getName().equals("index.adoc")) {
markupFileGenerated = true;
String markupContent = FileUtils.readFileToString(file, StandardCharsets.UTF_8);
Assert.assertTrue(markupContent.contains(":specDir: SPEC-DIR"),
"expected :specDir: in: " + markupContent.substring(0, 250));
Assert.assertTrue(markupContent.contains(":snippetDir: MY/SNIPPET/DIR"),
"expected :snippetDir: in: " + markupContent.substring(0, 250));
}
}
Assert.assertTrue(markupFileGenerated, "index.adoc is not generated!");
}
}

View File

@ -0,0 +1,82 @@
package org.openapitools.codegen.asciidoc;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import org.apache.commons.io.FileUtils;
import org.openapitools.codegen.DefaultGenerator;
import org.openapitools.codegen.config.CodegenConfigurator;
import org.openapitools.codegen.languages.AsciidocDocumentationCodegen;
import org.testng.Assert;
import org.testng.annotations.Test;
public class AsciidocSampleGeneratorTest {
/** ensure api-docs.json includes sample and spec files into markup. */
@Test
public void testSampleAsciidocMarkupGenerationFromJsonWithSpecsAndSamples() throws Exception {
File outputTempDirectory = Files.createTempDirectory("test-asciidoc-sample-generator.").toFile();
File specDir = new File("src/test/resources/3_0/asciidoc/specs/");
File snippetDir = new File("src/test/resources/3_0/asciidoc/generated-snippets/");
Assert.assertTrue(specDir.exists(), "test cancel, not specdDir found to use." + specDir.getPath());
Assert.assertTrue(snippetDir.exists(), "test cancel, not snippedDir found to use." + snippetDir.getPath());
final CodegenConfigurator configurator = new CodegenConfigurator().setGeneratorName("asciidoc")
.setInputSpec("src/test/resources/3_0/asciidoc/api-docs.json")
.setOutputDir(outputTempDirectory.getAbsolutePath())
.addAdditionalProperty(AsciidocDocumentationCodegen.SPEC_DIR, specDir.toString())
.addAdditionalProperty(AsciidocDocumentationCodegen.SNIPPET_DIR, snippetDir.toString());
DefaultGenerator generator = new DefaultGenerator();
List<File> files = generator.opts(configurator.toClientOptInput()).generate();
boolean markupFileGenerated = false;
for (File file : files) {
if (file.getName().equals("index.adoc")) {
markupFileGenerated = true;
String markupContent = FileUtils.readFileToString(file, StandardCharsets.UTF_8);
// include correct values from cli.
Assert.assertTrue(markupContent.contains(":specDir: " + specDir.toString()),
"expected :specDir: in: " + markupContent.substring(0, 350));
Assert.assertTrue(markupContent.contains(":snippetDir: " + snippetDir.toString()),
"expected :snippetDir: in: " + markupContent.substring(0, 350));
// include correct markup from separate directories, relative links
Assert.assertTrue(markupContent.contains("include::rest/project/GET/spec.adoc[]"),
"expected project spec.adoc to be included in " + file.getAbsolutePath());
Assert.assertTrue(markupContent.contains("include::rest/project/GET/implementation.adoc[]"),
"expected project implementation.adoc to be included in " + file.getAbsolutePath());
Assert.assertTrue(markupContent.contains("include::rest/project/GET/http-request.adoc[]"),
"expected project http-request.adoc to be included in " + file.getAbsolutePath());
Assert.assertTrue(markupContent.contains("include::rest/project/GET/http-response.adoc[]"),
"expected project http-response.adoc to be included in " + file.getAbsolutePath());
Assert.assertTrue(markupContent.contains("link:rest/project/GET/GET.json["),
"expected link: not found in file: " + file.getAbsoluteFile());
// extract correct value from json
Assert.assertTrue(markupContent.contains("= time@work rest api"),
"missing main header for api spec from json: " + markupContent.substring(0, 100));
}
Files.deleteIfExists(Paths.get(file.getAbsolutePath()));
}
Assert.assertTrue(markupFileGenerated, "index.adoc is not generated!");
Files.deleteIfExists(Paths.get(outputTempDirectory.getAbsolutePath(), ".openapi-generator"));
Files.deleteIfExists(Paths.get(outputTempDirectory.getAbsolutePath()));
}
}

View File

@ -0,0 +1,48 @@
package org.openapitools.codegen.asciidoc;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import org.mockito.MockitoAnnotations;
import org.openapitools.codegen.languages.AsciidocDocumentationCodegen;
import org.openapitools.codegen.templating.mustache.LambdaTest;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import org.testng.Assert;
public class IncludeMarkupFilterTest extends LambdaTest {
@BeforeMethod
public void setup() {
MockitoAnnotations.initMocks(this);
}
@Test
public void testIncludeMarkupFilterDoesNotIncludeMissingFile() {
final AsciidocDocumentationCodegen generator = new AsciidocDocumentationCodegen();
final Map<String, Object> ctx = context("specinclude", generator.new IncludeMarkupLambda("DOES_NOT_EXIST"));
final String result = execute("{{#specinclude}}not.an.existing.file.adoc{{/specinclude}}", ctx);
Assert.assertTrue(result.contains("// markup not found, no include ::not.an.existing.file.adoc[]"),
"unexpected filtered " + result);
}
@Test
public void testIncludeMarkupFilterFoundFileOk() throws IOException {
File tempFile = File.createTempFile("IncludeMarkupFilterTestDummyfile", "-adoc");
tempFile.deleteOnExit();
final AsciidocDocumentationCodegen generator = new AsciidocDocumentationCodegen();
final Map<String, Object> ctx = context("snippetinclude",
generator.new IncludeMarkupLambda(tempFile.getParent()));
final String result = execute("{{#snippetinclude}}" + tempFile.getName() + "{{/snippetinclude}}", ctx);
Assert.assertTrue(result.contains("include::"), "unexpected filtered: " + result);
Assert.assertTrue(result.contains(tempFile.getName()), "unexpected filtered: " + result);
}
}

View File

@ -0,0 +1,47 @@
package org.openapitools.codegen.asciidoc;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import org.mockito.MockitoAnnotations;
import org.openapitools.codegen.languages.AsciidocDocumentationCodegen;
import org.openapitools.codegen.templating.mustache.LambdaTest;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import org.testng.Assert;
public class LinkMarkupFilterTest extends LambdaTest {
@BeforeMethod
public void setup() {
MockitoAnnotations.initMocks(this);
}
@Test
public void testLinkMarkupFilterDoesNotLinkMissingFile() {
final AsciidocDocumentationCodegen generator = new AsciidocDocumentationCodegen();
final Map<String, Object> ctx = context("link", generator.new LinkMarkupLambda("DOES_NOT_EXIST"));
final String result = execute("{{#link}}not.an.existing.file.adoc{{/link}}", ctx);
Assert.assertTrue(result.contains("// file not found, no"), "unexpected filtered: " + result);
}
@Test
public void testLinkMarkupFilterLinksFoundFileOk() throws IOException {
File tempFile = File.createTempFile("LinkMarkupFilterTestDummyfile", ".adoc");
tempFile.deleteOnExit();
final AsciidocDocumentationCodegen generator = new AsciidocDocumentationCodegen();
final Map<String, Object> ctx = context("linkIntoMarkup", generator.new LinkMarkupLambda(tempFile.getParent()));
final String result = execute("{{#linkIntoMarkup}}my link text, " + tempFile.getName() + "{{/linkIntoMarkup}}",
ctx);
Assert.assertTrue(result.contains("link:"), "unexpected filtered: " + result);
Assert.assertTrue(result.contains(tempFile.getName() + "[]"), "unexpected filtered: " + result);
}
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,16 @@
{
"id" : "238a47e3-2533-41a4-ac62-f6654c936ada",
"request" : {
"url" : "/rest/project/",
"method" : "GET"
},
"response" : {
"status" : 200,
"body" : "[{\"id\":-3,\"name\":\"a third inactive project\",\"active\":false,\"projectLeads\":[{\"id\":-2,\"name\":\"another second lead\",\"userId\":\"tlead2\"},{\"id\":-1,\"name\":\"a first test lead and user\",\"userId\":\"tlead1\"}]},{\"id\":-2,\"name\":\"a second active project\",\"active\":true,\"projectLeads\":[{\"id\":-1,\"name\":\"a first test lead and user\",\"userId\":\"tlead1\"}]},{\"id\":-1,\"name\":\"a first active project\",\"active\":true,\"projectLeads\":[{\"id\":-2,\"name\":\"another second lead\",\"userId\":\"tlead2\"},{\"id\":-1,\"name\":\"a first test lead and user\",\"userId\":\"tlead1\"}]}]",
"headers" : {
"Vary" : [ "Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers" ],
"Content-Type" : "application/json"
}
},
"uuid" : "238a47e3-2533-41a4-ac62-f6654c936ada"
}

View File

@ -0,0 +1,4 @@
[source,bash]
----
$ curl 'http://samplehost.timeatwork.manathome.org:8080/rest/project/' -i -X GET
----

View File

@ -0,0 +1,6 @@
[source,http,options="nowrap"]
----
GET /rest/project/ HTTP/1.1
Host: samplehost.timeatwork.manathome.org:8080
----

View File

@ -0,0 +1,11 @@
[source,http,options="nowrap"]
----
HTTP/1.1 200 OK
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Content-Type: application/json;charset=UTF-8
Content-Length: 530
[{"id":-3,"name":"a third inactive project","active":false,"projectLeads":[{"id":-1,"name":"a first test lead and user","userId":"tlead1"},{"id":-2,"name":"another second lead","userId":"tlead2"}]},{"id":-2,"name":"a second active project","active":true,"projectLeads":[{"id":-1,"name":"a first test lead and user","userId":"tlead1"}]},{"id":-1,"name":"a first active project","active":true,"projectLeads":[{"id":-1,"name":"a first test lead and user","userId":"tlead1"},{"id":-2,"name":"another second lead","userId":"tlead2"}]}]
----

View File

@ -0,0 +1,4 @@
[source,bash]
----
$ http GET 'http://samplehost.timeatwork.manathome.org:8080/rest/project/'
----

View File

@ -0,0 +1,4 @@
[source,options="nowrap"]
----
----

View File

@ -0,0 +1,4 @@
[source,options="nowrap"]
----
[{"id":-3,"name":"a third inactive project","active":false,"projectLeads":[{"id":-1,"name":"a first test lead and user","userId":"tlead1"},{"id":-2,"name":"another second lead","userId":"tlead2"}]},{"id":-2,"name":"a second active project","active":true,"projectLeads":[{"id":-1,"name":"a first test lead and user","userId":"tlead1"}]},{"id":-1,"name":"a first active project","active":true,"projectLeads":[{"id":-1,"name":"a first test lead and user","userId":"tlead1"},{"id":-2,"name":"another second lead","userId":"tlead2"}]}]
----

View File

@ -0,0 +1,2 @@
// optional, conditionally included implementation notes.

View File

@ -0,0 +1,7 @@
// spec to include
* all _projects_ visible for the _current user_ are returned
* _projects_ may be active or closed
USER: project lead, admin

View File

@ -0,0 +1,23 @@
# OpenAPI Generator Ignore
# Generated by openapi-generator https://github.com/openapitools/openapi-generator
# Use this file to prevent files from being overwritten by the generator.
# The patterns follow closely to .gitignore or .dockerignore.
# As an example, the C# client generator defines ApiClient.cs.
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
#ApiClient.cs
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
#foo/*/qux
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
#foo/**/qux
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
# You can also negate patterns with an exclamation (!).
# For example, you can ignore all files in a docs folder with the file extension .md:
#docs/*.md
# Then explicitly reverse the ignore rule for a single file:
#!docs/README.md

View File

@ -0,0 +1 @@
unset

File diff suppressed because it is too large Load Diff