Skip to content

Commit a579c5b

Browse files
authored
Merge pull request #46 from jmini/merge_master_into_snapshot
Merge master into swagger-snapshot
2 parents 624d66d + e2bc81a commit a579c5b

File tree

70 files changed

+1319
-546
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+1319
-546
lines changed

Dockerfile

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
FROM maven:3.5-jdk-8-alpine as build
2+
WORKDIR /app
3+
COPY ./ /app
4+
RUN mvn install -q && \
5+
mvn package -q && \
6+
ls /app/target/ && \
7+
MVN_VERSION=$(mvn -q \
8+
-Dexec.executable="echo" \
9+
-Dexec.args='${project.version}' \
10+
--non-recursive \
11+
org.codehaus.mojo:exec-maven-plugin:1.6.0:exec) && \
12+
mv /app/target/openapi-diff-${MVN_VERSION}-jar-with-dependencies.jar /app/openapi-diff.jar
13+
14+
FROM openjdk:8-jre-alpine
15+
WORKDIR /app
16+
COPY --from=0 /app/openapi-diff.jar /app
17+
ENTRYPOINT ["java", "-jar", "/app/openapi-diff.jar"]
18+
CMD ["--help"]

README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,33 @@ Available on [Maven Central](https://search.maven.org/#search%7Cgav%7C1%7Cg%3A%2
2626
</dependency>
2727
```
2828

29+
# Docker
30+
31+
Available on [Docker Hub](https://hub.docker.com/r/quen2404/openapi-diff/) as `quen2404/openapi-diff`.
32+
33+
## Build the image
34+
35+
This is only required if you want to try new changes in the Dockerfile of this project.
36+
37+
```bash
38+
docker build -t local-openapi-diff .
39+
```
40+
41+
You can replace the local image name `local-openapi-diff` by any name of your choice.
42+
43+
## Run an instance
44+
45+
In this example the `$(pwd)/src/test/resources` directory is mounted in the `/specs` directory of the container
46+
in readonly mode (`ro`).
47+
48+
```bash
49+
docker run -t \
50+
-v $(pwd)/src/test/resources:/specs:ro \
51+
quen2404/openapi-diff /specs/path_1.yaml /specs/path_2.yaml
52+
```
53+
54+
The remote name `quen2404/openapi-diff` can be replaced with `local-openapi-diff` or the name you gave to your local image.
55+
2956
# Usage
3057
OpenDiff can read swagger api spec from json file or http.
3158

@@ -102,6 +129,11 @@ try {
102129
}
103130
```
104131

132+
### Extensions
133+
This project uses Java Service Provider Inteface (SPI) so additional extensions can be added.
134+
135+
To build your own extension, you simply need to create a `src/main/resources/META-INF/services/com.qdesrame.openapi.diff.compare.ExtensionDiff` file with the full classname of your implementation. Your class must also implement the `com.qdesrame.openapi.diff.compare.ExtensionDiff` interface. Then, including your library with the `openapi-diff` module will cause it to be triggered automatically.
136+
105137
# Example
106138
### CLI Output
107139

pom.xml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
<groupId>com.qdesrame</groupId>
1111
<artifactId>openapi-diff</artifactId>
12-
<version>1.2.1-SNAPSHOT</version>
12+
<version>2.0.0-SNAPSHOT</version>
1313
<packaging>jar</packaging>
1414

1515
<name>openapi-diff</name>
@@ -216,6 +216,15 @@
216216
<descriptorRef>jar-with-dependencies</descriptorRef>
217217
</descriptorRefs>
218218
</configuration>
219+
<executions>
220+
<execution>
221+
<id>make-assembly</id>
222+
<phase>package</phase>
223+
<goals>
224+
<goal>single</goal>
225+
</goals>
226+
</execution>
227+
</executions>
219228
</plugin>
220229
</plugins>
221230
</build>

src/main/java/com/qdesrame/openapi/diff/Main.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,10 +131,10 @@ public static void main(String... args) {
131131
}
132132
}
133133
if (line.hasOption("state")) {
134-
System.out.println(result.isDiff() ? result.isDiffBackwardCompatible() ? "compatible" : "incompatible" : "no_changes");
134+
System.out.println(result.isChanged().getValue());
135135
System.exit(0);
136136
} else {
137-
System.exit(result.isDiff() ? 1 : 0);
137+
System.exit(result.isUnchanged() ? 0 : 1);
138138
}
139139
} catch (ParseException e) {
140140
// oops, something went wrong

src/main/java/com/qdesrame/openapi/diff/compare/ApiResponseDiff.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.qdesrame.openapi.diff.model.ChangedApiResponse;
44
import com.qdesrame.openapi.diff.model.ChangedResponse;
5+
import com.qdesrame.openapi.diff.model.DiffContext;
56
import io.swagger.v3.oas.models.responses.ApiResponse;
67
import io.swagger.v3.oas.models.responses.ApiResponses;
78

@@ -10,6 +11,8 @@
1011
import java.util.Map;
1112
import java.util.Optional;
1213

14+
import static com.qdesrame.openapi.diff.utils.ChangedUtils.isChanged;
15+
1316
/**
1417
* Created by adarsh.sharma on 04/01/18.
1518
*/
@@ -20,19 +23,18 @@ public ApiResponseDiff(OpenApiDiff openApiDiff) {
2023
this.openApiDiff = openApiDiff;
2124
}
2225

23-
public Optional<ChangedApiResponse> diff(ApiResponses left, ApiResponses right) {
26+
public Optional<ChangedApiResponse> diff(ApiResponses left, ApiResponses right, DiffContext context) {
2427
MapKeyDiff<String, ApiResponse> responseMapKeyDiff = MapKeyDiff.diff(left, right);
25-
ChangedApiResponse changedApiResponse = new ChangedApiResponse(left, right);
28+
ChangedApiResponse changedApiResponse = new ChangedApiResponse(left, right, context);
2629
changedApiResponse.setAddResponses(responseMapKeyDiff.getIncreased());
2730
changedApiResponse.setMissingResponses(responseMapKeyDiff.getMissing());
2831
List<String> sharedResponseCodes = responseMapKeyDiff.getSharedKey();
29-
3032
Map<String, ChangedResponse> resps = new HashMap<>();
3133
for (String responseCode : sharedResponseCodes) {
32-
openApiDiff.getResponseDiff().diff(left.get(responseCode), right.get(responseCode))
34+
openApiDiff.getResponseDiff().diff(left.get(responseCode), right.get(responseCode), context)
3335
.ifPresent(changedResponse -> resps.put(responseCode, changedResponse));
3436
}
3537
changedApiResponse.setChangedResponses(resps);
36-
return changedApiResponse.isDiff() ? Optional.of(changedApiResponse) : Optional.empty();
38+
return isChanged(changedApiResponse);
3739
}
3840
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package com.qdesrame.openapi.diff.compare;
2+
3+
import com.qdesrame.openapi.diff.model.DiffContext;
4+
import lombok.Getter;
5+
import org.apache.commons.lang3.builder.EqualsBuilder;
6+
import org.apache.commons.lang3.builder.HashCodeBuilder;
7+
8+
@Getter
9+
public final class CacheKey {
10+
private final String left;
11+
private final String right;
12+
private final DiffContext context;
13+
14+
public CacheKey(final String left, final String right, final DiffContext context) {
15+
this.left = left;
16+
this.right = right;
17+
this.context = context;
18+
}
19+
20+
@Override
21+
public boolean equals(Object o) {
22+
if (this == o) return true;
23+
24+
if (o == null || getClass() != o.getClass()) return false;
25+
26+
CacheKey cacheKey = (CacheKey) o;
27+
28+
return new EqualsBuilder()
29+
.append(left, cacheKey.left)
30+
.append(right, cacheKey.right)
31+
.append(context, cacheKey.context)
32+
.isEquals();
33+
}
34+
35+
@Override
36+
public int hashCode() {
37+
return new HashCodeBuilder(17, 37)
38+
.append(left)
39+
.append(right)
40+
.append(context)
41+
.toHashCode();
42+
}
43+
}

src/main/java/com/qdesrame/openapi/diff/compare/ContentDiff.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@
22

33
import com.qdesrame.openapi.diff.model.ChangedContent;
44
import com.qdesrame.openapi.diff.model.ChangedMediaType;
5+
import com.qdesrame.openapi.diff.model.DiffContext;
56
import io.swagger.v3.oas.models.media.Content;
67
import io.swagger.v3.oas.models.media.MediaType;
78

89
import java.util.*;
910

11+
import static com.qdesrame.openapi.diff.utils.ChangedUtils.isChanged;
12+
import static com.qdesrame.openapi.diff.utils.ChangedUtils.isUnchanged;
13+
1014
public class ContentDiff implements Comparable<Content> {
1115

1216
private OpenApiDiff openApiDiff;
@@ -20,8 +24,8 @@ public boolean compare(Content left, Content right) {
2024
return false;
2125
}
2226

23-
public Optional<ChangedContent> diff(Content left, Content right) {
24-
ChangedContent changedContent = new ChangedContent(left, right);
27+
public Optional<ChangedContent> diff(Content left, Content right, DiffContext context) {
28+
ChangedContent changedContent = new ChangedContent(left, right, context);
2529

2630
MapKeyDiff<String, MediaType> mediaTypeDiff = MapKeyDiff.diff(left, right);
2731
changedContent.setIncreased(mediaTypeDiff.getIncreased());
@@ -31,13 +35,13 @@ public Optional<ChangedContent> diff(Content left, Content right) {
3135
for (String mediaTypeKey : sharedMediaTypes) {
3236
MediaType oldMediaType = left.get(mediaTypeKey);
3337
MediaType newMediaType = right.get(mediaTypeKey);
34-
ChangedMediaType changedMediaType = new ChangedMediaType(oldMediaType.getSchema(), newMediaType.getSchema());
35-
openApiDiff.getSchemaDiff().diff(new HashSet<>(), oldMediaType.getSchema(), newMediaType.getSchema()).ifPresent(changedMediaType::setChangedSchema);
36-
if (changedMediaType.isDiff()) {
38+
ChangedMediaType changedMediaType = new ChangedMediaType(oldMediaType.getSchema(), newMediaType.getSchema(), context);
39+
openApiDiff.getSchemaDiff().diff(new HashSet<>(), oldMediaType.getSchema(), newMediaType.getSchema(), context.copyWithRequired(true)).ifPresent(changedMediaType::setChangedSchema);
40+
if (!isUnchanged(changedMediaType)) {
3741
changedMediaTypes.put(mediaTypeKey, changedMediaType);
3842
}
3943
}
4044
changedContent.setChanged(changedMediaTypes);
41-
return changedContent.isDiff() ? Optional.of(changedContent) : Optional.empty();
45+
return isChanged(changedContent);
4246
}
4347
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.qdesrame.openapi.diff.compare;
2+
3+
import com.qdesrame.openapi.diff.model.Changed;
4+
import com.qdesrame.openapi.diff.model.DiffContext;
5+
6+
import java.util.Optional;
7+
8+
public interface ExtensionDiff {
9+
10+
ExtensionDiff setOpenApiDiff(OpenApiDiff openApiDiff);
11+
12+
String getName();
13+
14+
Optional<Changed> diff(Object left, Object right, DiffContext context);
15+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package com.qdesrame.openapi.diff.compare;
2+
3+
import com.qdesrame.openapi.diff.model.DiffContext;
4+
import com.qdesrame.openapi.diff.model.schema.ChangedExtensions;
5+
6+
import java.util.*;
7+
8+
import static com.qdesrame.openapi.diff.utils.ChangedUtils.isChanged;
9+
10+
public class ExtensionsDiff {
11+
private final OpenApiDiff openApiDiff;
12+
13+
private ServiceLoader<ExtensionDiff> extensionsLoader = ServiceLoader.load(ExtensionDiff.class);
14+
private List<ExtensionDiff> extensionsDiff = new ArrayList<>();
15+
16+
public ExtensionsDiff(OpenApiDiff openApiDiff) {
17+
this.openApiDiff = openApiDiff;
18+
this.extensionsLoader.reload();
19+
for (ExtensionDiff anExtensionsLoader : this.extensionsLoader) {
20+
extensionsDiff.add(anExtensionsLoader);
21+
}
22+
}
23+
24+
public Optional<ChangedExtensions> diff(Map<String, Object> left, Map<String, Object> right, DiffContext context) {
25+
if (null == left) left = new HashMap<>();
26+
if (null == right) right = new HashMap<>();
27+
ChangedExtensions changedExtensions = new ChangedExtensions(left, new HashMap<>(right), context);
28+
changedExtensions.getIncreased().putAll(right);
29+
for (String key : left.keySet()) {
30+
if (changedExtensions.getIncreased().containsKey(key)) {
31+
Optional<ExtensionDiff> extensionDiff = extensionsDiff.stream()
32+
.filter(diff -> ("x-" + diff.getName()).equals(key)).findFirst();
33+
Object leftValue = left.get(key);
34+
Object rightValue = changedExtensions.getIncreased().remove(key);
35+
extensionDiff.ifPresent(diff -> diff.setOpenApiDiff(openApiDiff).diff(leftValue, rightValue, context)
36+
.ifPresent(changed -> changedExtensions.getChanged().put(key, changed)));
37+
} else {
38+
changedExtensions.getMissing().put(key, left.get(key));
39+
}
40+
}
41+
return isChanged(changedExtensions);
42+
}
43+
}

src/main/java/com/qdesrame/openapi/diff/compare/HeaderDiff.java

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.qdesrame.openapi.diff.compare;
22

33
import com.qdesrame.openapi.diff.model.ChangedHeader;
4+
import com.qdesrame.openapi.diff.model.DiffContext;
45
import com.qdesrame.openapi.diff.utils.RefPointer;
56
import com.qdesrame.openapi.diff.utils.RefType;
67
import io.swagger.v3.oas.models.Components;
@@ -10,6 +11,8 @@
1011
import java.util.Objects;
1112
import java.util.Optional;
1213

14+
import static com.qdesrame.openapi.diff.utils.ChangedUtils.isChanged;
15+
1316
/**
1417
* Created by adarsh.sharma on 28/12/17.
1518
*/
@@ -25,26 +28,26 @@ public HeaderDiff(OpenApiDiff openApiDiff) {
2528
this.rightComponents = openApiDiff.getNewSpecOpenApi() != null ? openApiDiff.getNewSpecOpenApi().getComponents() : null;
2629
}
2730

28-
public Optional<ChangedHeader> diff(Header left, Header right) {
29-
return cachedDiff(new HashSet<>(), left, right, left.get$ref(), right.get$ref());
31+
public Optional<ChangedHeader> diff(Header left, Header right, DiffContext context) {
32+
return cachedDiff(new HashSet<>(), left, right, left.get$ref(), right.get$ref(), context);
3033
}
3134

3235
@Override
33-
protected Optional<ChangedHeader> computeDiff(HashSet<String> refSet, Header left, Header right) {
36+
protected Optional<ChangedHeader> computeDiff(HashSet<String> refSet, Header left, Header right, DiffContext context) {
3437
left = refPointer.resolveRef(leftComponents, left, left.get$ref());
3538
right = refPointer.resolveRef(rightComponents, right, right.get$ref());
3639

37-
ChangedHeader changedHeader = new ChangedHeader(left, right);
40+
ChangedHeader changedHeader = new ChangedHeader(left, right, context);
3841

3942
changedHeader.setChangeDescription(!Objects.equals(left.getDescription(), right.getDescription()));
4043
changedHeader.setChangeRequired(getBooleanDiff(left.getRequired(), right.getRequired()));
4144
changedHeader.setChangeDeprecated(!Boolean.TRUE.equals(left.getDeprecated()) && Boolean.TRUE.equals(right.getDeprecated()));
4245
changedHeader.setChangeStyle(!Objects.equals(left.getStyle(), right.getStyle()));
4346
changedHeader.setChangeExplode(getBooleanDiff(left.getExplode(), right.getExplode()));
44-
openApiDiff.getSchemaDiff().diff(new HashSet<>(), left.getSchema(), right.getSchema()).ifPresent(changedHeader::setChangedSchema);
45-
openApiDiff.getContentDiff().diff(left.getContent(), right.getContent()).ifPresent(changedHeader::setChangedContent);
47+
openApiDiff.getSchemaDiff().diff(new HashSet<>(), left.getSchema(), right.getSchema(), context.copyWithRequired(true)).ifPresent(changedHeader::setChangedSchema);
48+
openApiDiff.getContentDiff().diff(left.getContent(), right.getContent(), context).ifPresent(changedHeader::setChangedContent);
4649

47-
return changedHeader.isDiff() ? Optional.of(changedHeader) : Optional.empty();
50+
return isChanged(changedHeader);
4851
}
4952

5053
private boolean getBooleanDiff(Boolean left, Boolean right) {

0 commit comments

Comments
 (0)