Skip to content

Commit

Permalink
Merge 74913b4 into 99006c9
Browse files Browse the repository at this point in the history
  • Loading branch information
wwerner committed May 22, 2018
2 parents 99006c9 + 74913b4 commit cc76916
Show file tree
Hide file tree
Showing 10 changed files with 402 additions and 356 deletions.
7 changes: 7 additions & 0 deletions .gitignore
Expand Up @@ -15,3 +15,10 @@
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
/target/
.idea
swagger-diff.iml
testDiff.html
testDiff.md
testDeprecatedApi.html
testNewApi.html

7 changes: 1 addition & 6 deletions pom.xml
Expand Up @@ -10,7 +10,7 @@

<groupId>com.deepoove</groupId>
<artifactId>swagger-diff</artifactId>
<version>1.2.0</version>
<version>1.3.0-SNAPSHOT</version>
<packaging>jar</packaging>

<name>swagger-diff</name>
Expand Down Expand Up @@ -80,11 +80,6 @@
<artifactId>jcommander</artifactId>
<version>1.72</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>1.6.3</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
Expand Down
142 changes: 12 additions & 130 deletions src/main/java/com/deepoove/swagger/diff/SwaggerDiff.java
@@ -1,32 +1,18 @@
package com.deepoove.swagger.diff;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.deepoove.swagger.diff.compare.MapKeyDiff;
import com.deepoove.swagger.diff.compare.ParameterDiff;
import com.deepoove.swagger.diff.compare.PropertyDiff;
import com.deepoove.swagger.diff.compare.SpecificationDiff;
import com.deepoove.swagger.diff.model.ChangedEndpoint;
import com.deepoove.swagger.diff.model.ChangedOperation;
import com.deepoove.swagger.diff.model.Endpoint;
import com.fasterxml.jackson.databind.JsonNode;

import io.swagger.models.HttpMethod;
import io.swagger.models.Operation;
import io.swagger.models.Path;
import io.swagger.models.Response;
import io.swagger.models.Swagger;
import io.swagger.models.auth.AuthorizationValue;
import io.swagger.models.parameters.Parameter;
import io.swagger.models.properties.Property;
import io.swagger.parser.SwaggerCompatConverter;
import io.swagger.parser.SwaggerParser;

Expand Down Expand Up @@ -119,124 +105,13 @@ private SwaggerDiff(JsonNode oldSpec, JsonNode newSpec) {
}

private SwaggerDiff compare() {
Map<String, Path> oldPaths = oldSpecSwagger.getPaths();
Map<String, Path> newPaths = newSpecSwagger.getPaths();
MapKeyDiff<String, Path> pathDiff = MapKeyDiff.diff(oldPaths, newPaths);
this.newEndpoints = convert2EndpointList(pathDiff.getIncreased());
this.missingEndpoints = convert2EndpointList(pathDiff.getMissing());

this.changedEndpoints = new ArrayList<ChangedEndpoint>();

List<String> sharedKey = pathDiff.getSharedKey();
ChangedEndpoint changedEndpoint = null;
for (String pathUrl : sharedKey) {
changedEndpoint = new ChangedEndpoint();
changedEndpoint.setPathUrl(pathUrl);
Path oldPath = oldPaths.get(pathUrl);
Path newPath = newPaths.get(pathUrl);

Map<HttpMethod, Operation> oldOperationMap = oldPath.getOperationMap();
Map<HttpMethod, Operation> newOperationMap = newPath.getOperationMap();
MapKeyDiff<HttpMethod, Operation> operationDiff = MapKeyDiff.diff(oldOperationMap,
newOperationMap);
Map<HttpMethod, Operation> increasedOperation = operationDiff.getIncreased();
Map<HttpMethod, Operation> missingOperation = operationDiff.getMissing();
changedEndpoint.setNewOperations(increasedOperation);
changedEndpoint.setMissingOperations(missingOperation);

List<HttpMethod> sharedMethods = operationDiff.getSharedKey();
Map<HttpMethod, ChangedOperation> operas = new HashMap<HttpMethod, ChangedOperation>();
ChangedOperation changedOperation = null;
for (HttpMethod method : sharedMethods) {
changedOperation = new ChangedOperation();
Operation oldOperation = oldOperationMap.get(method);
Operation newOperation = newOperationMap.get(method);
changedOperation.setSummary(newOperation.getSummary());

List<Parameter> oldParameters = oldOperation.getParameters();
List<Parameter> newParameters = newOperation.getParameters();
ParameterDiff parameterDiff = ParameterDiff
.buildWithDefinition(oldSpecSwagger.getDefinitions(),
newSpecSwagger.getDefinitions())
.diff(oldParameters, newParameters);
changedOperation.setAddParameters(parameterDiff.getIncreased());
changedOperation.setMissingParameters(parameterDiff.getMissing());
changedOperation.setChangedParameter(parameterDiff.getChanged());

Property oldResponseProperty = getResponseProperty(oldOperation);
Property newResponseProperty = getResponseProperty(newOperation);
PropertyDiff propertyDiff = PropertyDiff.buildWithDefinition(
oldSpecSwagger.getDefinitions(), newSpecSwagger.getDefinitions());
propertyDiff.diff(oldResponseProperty, newResponseProperty);
changedOperation.setAddProps(propertyDiff.getIncreased());
changedOperation.setMissingProps(propertyDiff.getMissing());

if (changedOperation.isDiff()) {
operas.put(method, changedOperation);
}
}
changedEndpoint.setChangedOperations(operas);

this.newEndpoints.addAll(convert2EndpointList(changedEndpoint.getPathUrl(),
changedEndpoint.getNewOperations()));
this.missingEndpoints.addAll(convert2EndpointList(changedEndpoint.getPathUrl(),
changedEndpoint.getMissingOperations()));

if (changedEndpoint.isDiff()) {
changedEndpoints.add(changedEndpoint);
}
}

SpecificationDiff diff = SpecificationDiff.diff(oldSpecSwagger, newSpecSwagger);
this.newEndpoints = diff.getNewEndpoints();
this.missingEndpoints = diff.getMissingEndpoints();
this.changedEndpoints = diff.getChangedEndpoints();
return this;
}

private Property getResponseProperty(Operation operation) {
Map<String, Response> responses = operation.getResponses();
Response response = responses.get("200");
return null == response ? null : response.getSchema();
}

private List<Endpoint> convert2EndpointList(Map<String, Path> map) {
List<Endpoint> endpoints = new ArrayList<Endpoint>();
if (null == map) return endpoints;
for (Entry<String, Path> entry : map.entrySet()) {
String url = entry.getKey();
Path path = entry.getValue();

Map<HttpMethod, Operation> operationMap = path.getOperationMap();
for (Entry<HttpMethod, Operation> entryOper : operationMap.entrySet()) {
HttpMethod httpMethod = entryOper.getKey();
Operation operation = entryOper.getValue();

Endpoint endpoint = new Endpoint();
endpoint.setPathUrl(url);
endpoint.setMethod(httpMethod);
endpoint.setSummary(operation.getSummary());
endpoint.setPath(path);
endpoint.setOperation(operation);
endpoints.add(endpoint);
}
}
return endpoints;
}

private Collection<? extends Endpoint> convert2EndpointList(String pathUrl,
Map<HttpMethod, Operation> map) {
List<Endpoint> endpoints = new ArrayList<Endpoint>();
if (null == map) return endpoints;
for (Entry<HttpMethod, Operation> entry : map.entrySet()) {
HttpMethod httpMethod = entry.getKey();
Operation operation = entry.getValue();
Endpoint endpoint = new Endpoint();
endpoint.setPathUrl(pathUrl);
endpoint.setMethod(httpMethod);
endpoint.setSummary(operation.getSummary());
endpoint.setOperation(operation);
endpoints.add(endpoint);
}
return endpoints;
}

public List<Endpoint> getNewEndpoints() {
return newEndpoints;
}
Expand All @@ -249,4 +124,11 @@ public List<ChangedEndpoint> getChangedEndpoints() {
return changedEndpoints;
}

public String getOldVersion() {
return oldSpecSwagger.getInfo().getVersion();
}

public String getNewVersion() {
return newSpecSwagger.getInfo().getVersion();
}
}
174 changes: 174 additions & 0 deletions src/main/java/com/deepoove/swagger/diff/compare/SpecificationDiff.java
@@ -0,0 +1,174 @@
package com.deepoove.swagger.diff.compare;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import com.deepoove.swagger.diff.model.ChangedEndpoint;
import com.deepoove.swagger.diff.model.ChangedOperation;
import com.deepoove.swagger.diff.model.Endpoint;

import io.swagger.models.HttpMethod;
import io.swagger.models.Operation;
import io.swagger.models.Path;
import io.swagger.models.Response;
import io.swagger.models.Swagger;
import io.swagger.models.parameters.Parameter;
import io.swagger.models.properties.Property;

/**
* compare two Swagger
*
* @author Sayi
*
*/
public class SpecificationDiff {

private List<Endpoint> newEndpoints;
private List<Endpoint> missingEndpoints;
private List<ChangedEndpoint> changedEndpoints;

private SpecificationDiff() {
}

public static SpecificationDiff diff(Swagger oldSpec, Swagger newSpec) {
SpecificationDiff instance = new SpecificationDiff();
if (null == oldSpec || null == newSpec) {
throw new IllegalArgumentException("cannot diff null spec.");
}
Map<String, Path> oldPaths = oldSpec.getPaths();
Map<String, Path> newPaths = newSpec.getPaths();
MapKeyDiff<String, Path> pathDiff = MapKeyDiff.diff(oldPaths, newPaths);
instance.newEndpoints = convert2EndpointList(pathDiff.getIncreased());
instance.missingEndpoints = convert2EndpointList(pathDiff.getMissing());
instance.changedEndpoints = new ArrayList<ChangedEndpoint>();

List<String> sharedKey = pathDiff.getSharedKey();
ChangedEndpoint changedEndpoint = null;
for (String pathUrl : sharedKey) {
changedEndpoint = new ChangedEndpoint();
changedEndpoint.setPathUrl(pathUrl);
Path oldPath = oldPaths.get(pathUrl);
Path newPath = newPaths.get(pathUrl);

Map<HttpMethod, Operation> oldOperationMap = oldPath.getOperationMap();
Map<HttpMethod, Operation> newOperationMap = newPath.getOperationMap();
MapKeyDiff<HttpMethod, Operation> operationDiff = MapKeyDiff.diff(oldOperationMap, newOperationMap);
Map<HttpMethod, Operation> increasedOperation = operationDiff.getIncreased();
Map<HttpMethod, Operation> missingOperation = operationDiff.getMissing();
changedEndpoint.setNewOperations(increasedOperation);
changedEndpoint.setMissingOperations(missingOperation);

List<HttpMethod> sharedMethods = operationDiff.getSharedKey();
Map<HttpMethod, ChangedOperation> operas = new HashMap<HttpMethod, ChangedOperation>();
ChangedOperation changedOperation = null;
for (HttpMethod method : sharedMethods) {
changedOperation = new ChangedOperation();
Operation oldOperation = oldOperationMap.get(method);
Operation newOperation = newOperationMap.get(method);
changedOperation.setSummary(newOperation.getSummary());

List<Parameter> oldParameters = oldOperation.getParameters();
List<Parameter> newParameters = newOperation.getParameters();
ParameterDiff parameterDiff = ParameterDiff
.buildWithDefinition(oldSpec.getDefinitions(), newSpec.getDefinitions())
.diff(oldParameters, newParameters);
changedOperation.setAddParameters(parameterDiff.getIncreased());
changedOperation.setMissingParameters(parameterDiff.getMissing());
changedOperation.setChangedParameter(parameterDiff.getChanged());

Property oldResponseProperty = getResponseProperty(oldOperation);
Property newResponseProperty = getResponseProperty(newOperation);
PropertyDiff propertyDiff = PropertyDiff.buildWithDefinition(oldSpec.getDefinitions(),
newSpec.getDefinitions());
propertyDiff.diff(oldResponseProperty, newResponseProperty);
changedOperation.setAddProps(propertyDiff.getIncreased());
changedOperation.setMissingProps(propertyDiff.getMissing());

if (changedOperation.isDiff()) {
operas.put(method, changedOperation);
}
}
changedEndpoint.setChangedOperations(operas);

instance.newEndpoints
.addAll(convert2EndpointList(changedEndpoint.getPathUrl(), changedEndpoint.getNewOperations()));
instance.missingEndpoints
.addAll(convert2EndpointList(changedEndpoint.getPathUrl(), changedEndpoint.getMissingOperations()));

if (changedEndpoint.isDiff()) {
instance.changedEndpoints.add(changedEndpoint);
}
}

return instance;

}

private static Property getResponseProperty(Operation operation) {
Map<String, Response> responses = operation.getResponses();
// temporary workaround for missing response messages
if (responses == null)
return null;
Response response = responses.get("200");
return null == response ? null : response.getSchema();
}

private static List<Endpoint> convert2EndpointList(Map<String, Path> map) {
List<Endpoint> endpoints = new ArrayList<Endpoint>();
if (null == map)
return endpoints;
for (Entry<String, Path> entry : map.entrySet()) {
String url = entry.getKey();
Path path = entry.getValue();

Map<HttpMethod, Operation> operationMap = path.getOperationMap();
for (Entry<HttpMethod, Operation> entryOper : operationMap.entrySet()) {
HttpMethod httpMethod = entryOper.getKey();
Operation operation = entryOper.getValue();

Endpoint endpoint = new Endpoint();
endpoint.setPathUrl(url);
endpoint.setMethod(httpMethod);
endpoint.setSummary(operation.getSummary());
endpoint.setPath(path);
endpoint.setOperation(operation);
endpoints.add(endpoint);
}
}
return endpoints;
}

private static Collection<? extends Endpoint> convert2EndpointList(String pathUrl, Map<HttpMethod, Operation> map) {
List<Endpoint> endpoints = new ArrayList<Endpoint>();
if (null == map)
return endpoints;
for (Entry<HttpMethod, Operation> entry : map.entrySet()) {
HttpMethod httpMethod = entry.getKey();
Operation operation = entry.getValue();
Endpoint endpoint = new Endpoint();
endpoint.setPathUrl(pathUrl);
endpoint.setMethod(httpMethod);
endpoint.setSummary(operation.getSummary());
endpoint.setOperation(operation);
endpoints.add(endpoint);
}
return endpoints;
}

public List<Endpoint> getNewEndpoints() {
return newEndpoints;
}

public List<Endpoint> getMissingEndpoints() {
return missingEndpoints;
}

public List<ChangedEndpoint> getChangedEndpoints() {
return changedEndpoints;
}

}

0 comments on commit cc76916

Please sign in to comment.