diff --git a/.github/actions/action.yml b/.github/actions/action.yml
new file mode 100644
index 0000000000..ae316464d3
--- /dev/null
+++ b/.github/actions/action.yml
@@ -0,0 +1,40 @@
+name: 'Swagger Parser'
+description: 'Parses, validates, dereferences an OpenAPI definition'
+inputs:
+ inputSpec:
+ description: 'path to OpenAPI definition file'
+ required: true
+ options:
+ description: 'parser options'
+ required: false
+ serializationType:
+ description: 'result file serialization type'
+ required: false
+ logsPath:
+ description: 'path to validation result file'
+ required: false
+ parserSpecPath:
+ description: 'output path of the serialized parsed definition'
+ required: false
+ parserVersion:
+ description: 'parser version'
+ required: false
+runs:
+ using: "composite"
+ steps:
+ - id: java-version
+ run: java -version 2>&1 | fgrep -i version | cut -d'"' -f2 | sed -e 's/^1\./1\%/' -e 's/\..*//' -e 's/%/./'
+ shell: bash
+ - name: Build Java
+ if: steps.java-version == null || steps.java-version < 1.8
+ uses: actions/setup-java@v3
+ with:
+ distribution: 'zulu'
+ java-version: '11'
+ - name: Download JAR
+ run: curl -L 'https://repository.sonatype.org/service/local/artifact/maven/content?r=central-proxy&g=io.swagger.parser.v3&a=swagger-parser-cli&e=jar&v=${{ inputs.parserVersion }}' -o swagger-parser-cli.jar
+ shell: bash
+ - id: execute
+ name: Execute Jar
+ run: java -jar swagger-parser-cli.jar -i ${{ inputs.inputSpec }} ${{ inputs.options }} ${{ inputs.serializationType }} -o ${{ inputs.parserSpecPath }} -l ${{ inputs.logsPath }}
+ shell: bash
\ No newline at end of file
diff --git a/.github/workflows/validate-workflow.yml b/.github/workflows/validate-workflow.yml
new file mode 100644
index 0000000000..8c35c43e3a
--- /dev/null
+++ b/.github/workflows/validate-workflow.yml
@@ -0,0 +1,25 @@
+name: SwaggerParserCLI Test
+
+on: [push]
+
+jobs:
+ validate_job:
+ runs-on: ubuntu-latest
+ name: A job to validate a definition
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ ref: action
+ - uses: ./.github/actions/
+ with:
+ inputSpec: '/home/runner/work/swagger-parser/swagger-parser/modules/swagger-parser-cli/src/test/resources/fileWithNoErrorMessages.yaml'
+ options: '-resolve -resolveFully'
+ parserVersion: '2.1.2'
+ serializationType: '-json'
+ logsPath: '/home/runner/work/swagger-parser/swagger-parser/modules/swagger-parser-cli/target/test-classes/parserLogs.yaml'
+ parserSpecPath: '/home/runner/work/swagger-parser/swagger-parser/modules/swagger-parser-cli/target/test-classes/specParsed.json'
+ - run: cat /home/runner/work/swagger-parser/swagger-parser/modules/swagger-parser-cli/target/test-classes/specParsed.json
+ shell: bash
+
+
+
diff --git a/modules/swagger-parser-cli/pom.xml b/modules/swagger-parser-cli/pom.xml
index 5ba74616ca..00f993ae61 100644
--- a/modules/swagger-parser-cli/pom.xml
+++ b/modules/swagger-parser-cli/pom.xml
@@ -76,6 +76,16 @@
org.testng
testng
+
+ net.sourceforge.argparse4j
+ argparse4j
+ 0.9.0
+
+
+ org.slf4j
+ slf4j-simple
+ 2.0.0
+
diff --git a/modules/swagger-parser-cli/src/main/java/io/swagger/v3/parser/SwaggerParser.java b/modules/swagger-parser-cli/src/main/java/io/swagger/v3/parser/SwaggerParser.java
index 8fa2ec402a..904a31362c 100644
--- a/modules/swagger-parser-cli/src/main/java/io/swagger/v3/parser/SwaggerParser.java
+++ b/modules/swagger-parser-cli/src/main/java/io/swagger/v3/parser/SwaggerParser.java
@@ -1,31 +1,144 @@
package io.swagger.v3.parser;
+import io.swagger.v3.core.util.Json;
+import io.swagger.v3.core.util.Yaml;
+
+import io.swagger.v3.parser.core.models.ParseOptions;
import io.swagger.v3.parser.core.models.SwaggerParseResult;
+import net.sourceforge.argparse4j.ArgumentParsers;
+import net.sourceforge.argparse4j.impl.Arguments;
+import net.sourceforge.argparse4j.inf.ArgumentParser;
+import net.sourceforge.argparse4j.inf.ArgumentParserException;
+import net.sourceforge.argparse4j.inf.Namespace;
+
+
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
+
public class SwaggerParser {
+
+ public static final String RESOLVE = "resolve";
+ public static final String RESOLVEFULLY = "resolvefully";
+ public static final String FLATTEN = "flatten";
+
public static void main(String[] args) {
if (args.length > 0){
- List messages = readFromLocation(args[0]);
- if ( messages.size() > 0){
- messages.forEach(System.out::println);
+ ArgumentParser parser = ArgumentParsers.newFor("swagger-parser").build()
+ .defaultHelp(true);
+ parser.addArgument("-i")
+ .dest("i")
+ .required(true)
+ .type(String.class)
+ .help("input file to be parsed");
+ parser.addArgument("-resolve")
+ .dest(RESOLVE)
+ .type(Boolean.class)
+ .action(Arguments.storeTrue())
+ .setDefault(false)
+ .help("resolve remote or local references");
+ parser.addArgument("-resolveFully")
+ .dest(RESOLVEFULLY)
+ .type(Boolean.class)
+ .action(Arguments.storeTrue())
+ .setDefault(false)
+ .help("");
+ parser.addArgument("-flatten")
+ .dest(FLATTEN)
+ .type(Boolean.class)
+ .action(Arguments.storeTrue())
+ .setDefault(false)
+ .help("");
+ parser.addArgument("-o")
+ .dest("o")
+ .type(String.class)
+ .help("output file parsed");
+ parser.addArgument("-l")
+ .dest("l")
+ .type(String.class)
+ .help("output error logs");
+ parser.addArgument("-json")
+ .dest("json")
+ .type(String.class)
+ .help("generate file as JSON");
+ parser.addArgument("-yaml")
+ .dest("yaml")
+ .type(String.class)
+ .help("generate file as YAML");
+ try{
+ readFromLocation(parser.parseArgs(args));
+ }catch (ArgumentParserException e) {
+ parser.handleError(e);
System.exit(1);
}
}
}
- public static List readFromLocation(String location) {
+ private static void generateMessagesFile(List messages, Namespace arguments) {
+ if ( messages != null && !messages.isEmpty() && arguments != null && arguments.getString("l") != null){
+ if(arguments.getString("l") != null) {
+ generateParsedFile(arguments, "l", messages.toString());
+ }
+ }
+ }
+
+ public static List readFromLocation(Namespace args) {
List messages = new ArrayList<>();
+ ParseOptions options;
try {
- final SwaggerParseResult result = new OpenAPIV3Parser().readLocation(location, null, null);
+ options = setOptions(args);
+ final SwaggerParseResult result = new OpenAPIV3Parser().readLocation(args.get("i"), null, options);
+ if(args.getString("o") != null) {
+ if (result.getOpenAPI() != null){
+ String output;
+ if(args.getString("json") != null){
+ output = Json.pretty(result.getOpenAPI());
+ }else if(args.getString("yaml") != null){
+ output = Yaml.pretty(result.getOpenAPI());
+ }else{
+ output= Yaml.pretty(result.getOpenAPI());
+ }
+ generateParsedFile(args, "o", output );
+ }
+ }
if(result.getOpenAPI() == null || !result.getMessages().isEmpty()){
messages = result.getMessages();
+ generateMessagesFile(messages, args);
}
}catch (Exception e){
e.printStackTrace();
- System.exit(1);
}
return messages;
}
+
+ private static void generateParsedFile(Namespace args, String o, String result) {
+ try {
+ if(result != null) {
+ OutputStream out = Files.newOutputStream(Paths.get(args.getString(o)));
+ byte[] specBytes = result.getBytes();
+ out.write(specBytes);
+ out.close();
+ }
+ }catch (Exception e){
+ e.printStackTrace();
+ }
+ }
+
+ private static ParseOptions setOptions(Namespace parseOptions) {
+ ParseOptions options = new ParseOptions();
+
+ if (parseOptions.getString(RESOLVE) !=null && parseOptions.getString(RESOLVE).equals("true")) {
+ options.setResolve(true);
+ }
+ if (parseOptions.getString(RESOLVEFULLY) != null && parseOptions.getString(RESOLVEFULLY).equals("true")) {
+ options.setResolveFully(true);
+ }
+ if (parseOptions.getString(FLATTEN) != null && parseOptions.getString(FLATTEN).equals("true")) {
+ options.setFlatten(true);
+ }
+ return options;
+ }
}
\ No newline at end of file
diff --git a/modules/swagger-parser-cli/src/test/java/SwaggerParserCLITest.java b/modules/swagger-parser-cli/src/test/java/SwaggerParserCLITest.java
index fa68bd9568..064d2010d1 100644
--- a/modules/swagger-parser-cli/src/test/java/SwaggerParserCLITest.java
+++ b/modules/swagger-parser-cli/src/test/java/SwaggerParserCLITest.java
@@ -1,28 +1,120 @@
import io.swagger.v3.parser.SwaggerParser;
+import net.sourceforge.argparse4j.inf.ArgumentParserException;
+import net.sourceforge.argparse4j.inf.Namespace;
import org.testng.Assert;
import org.testng.annotations.Test;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
public class SwaggerParserCLITest {
@Test
public void validateOKFromLocationTest(){
- String []args = new String[1];
- args[0] = "src/test/resources/fileWithNoErrorMessages.yaml";
- Assert.assertTrue(SwaggerParser.readFromLocation(args[0]).size() == 0);
+ Map args = new HashMap();
+ args.put("i","src/test/resources/fileWithNoErrorMessages.yaml");
+ Namespace namespace = new Namespace(args);
+ Assert.assertTrue(SwaggerParser.readFromLocation(namespace).size() == 0);
}
@Test
public void validateErrorFromLocationTest(){
- String []args = new String[1];
- args[0] = "src/test/resources/fileWithValidationErrorMessages.yaml";
- Assert.assertEquals(SwaggerParser.readFromLocation(args[0]).get(0), "attribute info.version is missing");
- Assert.assertEquals(SwaggerParser.readFromLocation(args[0]).get(1), "attribute paths.'/cu'(post).responses.200.description is missing");
+ Map args = new HashMap();
+ args.put("i","src/test/resources/fileWithValidationErrorMessages.yaml");
+ Namespace namespace = new Namespace(args);
+ Assert.assertEquals(SwaggerParser.readFromLocation(namespace).toString(), "[attribute info.version is missing, attribute paths.'/cu'(post).responses.200.description is missing]");
+ }
+
+ @Test
+ public void validateErrorTest(){
+ Map args = new HashMap();
+ args.put("i","src/test/resources/fileWithValidationErrorMessages.yaml");
+ args.put("resolve", "true");
+ args.put("resolvefully", "true");
+ args.put("o", "target/test-classes/parsedSpec.yaml");
+ args.put("l", "target/test-classes/errorLogs.yaml");
+ Namespace namespace = new Namespace(args);
+ Assert.assertEquals(SwaggerParser.readFromLocation(namespace).toString(), "[attribute info.version is missing, attribute paths.'/cu'(post).responses.200.description is missing]");
}
@Test
public void validateFileNotFoundInLocationTest(){
- String []args = new String[1];
- args[0] = "src/test/resources/WrongLocation.yaml";
- Assert.assertTrue(SwaggerParser.readFromLocation(args[0]).size() == 1);
- Assert.assertEquals(SwaggerParser.readFromLocation(args[0]).get(0), "Unable to read location `src/test/resources/WrongLocation.yaml`");
+ Map args = new HashMap();
+ args.put("i","src/test/resources/WrongLocation.yaml");
+ args.put("l", "target/test-classes/errorLogs.yaml");
+ Namespace namespace = new Namespace(args);
+ List messages = new ArrayList<>();
+ try {
+ messages = SwaggerParser.readFromLocation(namespace);
+ }catch (Exception e){
+ Assert.fail("error");
+ }
+ Assert.assertTrue( messages.size() == 1);
+ Assert.assertEquals(messages.toString(), "[Unable to read location `src/test/resources/WrongLocation.yaml`]");
+ }
+
+ @Test
+ public void validateOKFromLocationWithResolveOptionTest(){
+ Map args = new HashMap();
+ args.put("i","src/test/resources/internal-references-in-external-files/main.yaml");
+ args.put("resolve", "true");
+ Namespace namespace = new Namespace(args);
+ Assert.assertTrue(SwaggerParser.readFromLocation(namespace).size() == 0);
+ }
+
+ @Test
+ public void validateOKFromLocationWithResolveFullyOptionTestYaml(){
+ Map args = new HashMap();
+ args.put("i","src/test/resources/internal-references-in-external-files/main.yaml");
+ args.put("resolve", "true");
+ args.put("resolvefully", "true");
+ args.put("yaml", "true");
+ args.put("o", "target/test-classes/parsedSpec.yaml");
+ Namespace namespace = new Namespace(args);
+ Path path = Paths.get("target/test-classes/parsedSpec.yaml");
+
+ Assert.assertTrue(SwaggerParser.readFromLocation(namespace).size() == 0);
+ Assert.assertTrue(Files.exists(path));
+ }
+
+ @Test
+ public void validateOKFromLocationWithResolveFullyOptionTestJson(){
+ Map args = new HashMap();
+ args.put("i","src/test/resources/internal-references-in-external-files/main.yaml");
+ args.put("resolve", "true");
+ args.put("resolvefully", "true");
+ args.put("json", "true");
+ args.put("o", "target/test-classes/parsedSpec.json");
+ Namespace namespace = new Namespace(args);
+ Path path = Paths.get("target/test-classes/parsedSpec.json");
+
+ Assert.assertTrue(SwaggerParser.readFromLocation(namespace).size() == 0);
+ Assert.assertTrue(Files.exists(path));
+ }
+
+ @Test
+ public void validateOKFromLocationWithOnlyResolveFullyOptionTest(){
+ Map args = new HashMap();
+ args.put("i","src/test/resources/internal-references-in-external-files/main.yaml");
+ args.put("resolvefully","true");
+ Namespace namespace = new Namespace(args);
+ Assert.assertTrue(SwaggerParser.readFromLocation(namespace).size() == 0);
+ }
+
+ @Test
+ public void validateOKFromLocationWithFlattenOptionTest() throws ArgumentParserException {
+ Map args = new HashMap();
+ args.put("i","src/test/resources/internal-references-in-external-files/main.yaml");
+ args.put("resolve", "true");
+ args.put("resolvefully", "true");
+ args.put("flatten", "true");
+ args.put("o", "target/test-classes/parsedSpec.yaml");
+ args.put("l", "target/test-classes/errorLogs.yaml");
+ Namespace namespace = new Namespace(args);
+ Assert.assertTrue(SwaggerParser.readFromLocation(namespace).size() == 0);
}
}
\ No newline at end of file
diff --git a/modules/swagger-parser-cli/src/test/resources/internal-references-in-external-files/external.yaml b/modules/swagger-parser-cli/src/test/resources/internal-references-in-external-files/external.yaml
new file mode 100644
index 0000000000..361c56fffd
--- /dev/null
+++ b/modules/swagger-parser-cli/src/test/resources/internal-references-in-external-files/external.yaml
@@ -0,0 +1,27 @@
+common:
+ allOf:
+ - $ref: "#/core"
+ - type: object
+ properties:
+ attribute:
+ type: string
+ direct:
+ $ref: "#/core"
+ referenced:
+ type: array
+ items:
+ $ref: "#/core"
+
+core:
+ type: object
+ properties:
+ coreAttribute:
+ type: string
+ inner:
+ $ref: "#/innerCore"
+
+innerCore:
+ type: object
+ properties:
+ innerCoreAttribute:
+ type: string
diff --git a/modules/swagger-parser-cli/src/test/resources/internal-references-in-external-files/main.yaml b/modules/swagger-parser-cli/src/test/resources/internal-references-in-external-files/main.yaml
new file mode 100644
index 0000000000..95e501c614
--- /dev/null
+++ b/modules/swagger-parser-cli/src/test/resources/internal-references-in-external-files/main.yaml
@@ -0,0 +1,29 @@
+openapi: 3.0.0
+info:
+ version: 0.0.1
+ title: API
+paths:
+ /:
+ post:
+ summary: Create
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/create'
+ responses:
+ '200':
+ description: Successful response
+components:
+ schemas:
+ create:
+ type: object
+ properties:
+ attribute:
+ type: string
+ direct:
+ $ref: "./external.yaml#/common"
+ referenced:
+ type: array
+ items:
+ $ref: "./external.yaml#/common"