Skip to content

Commit 04dad02

Browse files
enhance report with extensions etc. (#659)
* enhance report with extensions etc. * Improve capitalized errors regex
1 parent 1fc6d41 commit 04dad02

File tree

9 files changed

+361
-17
lines changed

9 files changed

+361
-17
lines changed

.github/workflows/go.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ jobs:
7676
- if: runner.os == 'Linux'
7777
name: Errors must not be capitalized https://github.com/golang/go/wiki/CodeReviewComments#error-strings
7878
run: |
79-
! git grep -E '(fmt|errors)[^(]+\(.[A-Z]'
79+
! git grep -E '(fmt\.Errorf|errors\.New)\(.[A-Z]'
8080
8181
# - if: runner.os == 'Linux'
8282
# name: Did you mean %q

data/request-body/base.yaml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
openapi: 3.0.1
2+
info:
3+
title: Tufin
4+
version: "1.0"
5+
paths:
6+
/api/v1.0/groups:
7+
post:
8+
operationId: createOneGroup
9+
requestBody:
10+
x-nonschema: true
11+
content:
12+
application/json:
13+
example: [1, 2, 3]
14+
examples:
15+
example1:
16+
value: [1, 2, 3]
17+
x-nonschema: true
18+
schema:
19+
x-nonschema: true
20+
type: array
21+
items:
22+
type: string
23+
application/xml:
24+
schema:
25+
type: array
26+
items:
27+
type: string
28+
description: Creates one project.
29+
required: true
30+
responses:
31+
"200":
32+
x-nonschema: true
33+
description: OK
34+
summary: Create One Project
35+
servers:
36+
- url: 'https://www.oasdiff.com'
37+
description: "1"
38+
variables:
39+
title:
40+
default: "CEO"
41+
x-extension-test:
42+
test: "test"
43+
x-nonschema: true

data/request-body/revision.yaml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
openapi: 3.0.1
2+
info:
3+
title: Tufin
4+
version: "1.0"
5+
paths:
6+
/api/v1.0/groups:
7+
post:
8+
operationId: createOneGroup
9+
requestBody:
10+
content:
11+
application/json:
12+
example: [1, 2, 3, 4]
13+
examples:
14+
example1:
15+
value: [1, 2, 3]
16+
schema:
17+
type: array
18+
items:
19+
type: number
20+
application/octet-stream:
21+
schema:
22+
type: array
23+
items:
24+
type: number
25+
description: Creates one project.
26+
required: true
27+
responses:
28+
"200":
29+
description: OK
30+
summary: Create One Project
31+
servers:
32+
- url: 'https://www.oasdiff.com'
33+
description: "1"
34+
variables:
35+
title:
36+
default: "CEO"
37+
x-nonschema: true
38+
x-extension-test:
39+
test: "test"
40+
x-nonschema: true

diff/json_diff.go

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,55 @@
11
package diff
22

33
import (
4+
"fmt"
5+
46
"github.com/wI2L/jsondiff"
57
)
68

7-
// jsonPatch is a wrapper to jsondiff.jsonPatch with proper serialization for json and yaml
8-
type jsonPatch []*jsonOperation
9+
// JsonPatch is a wrapper to jsondiff.JsonPatch with proper serialization for json and yaml
10+
type JsonPatch []*JsonOperation
911

1012
// Empty indicates whether a change was found in this element
11-
func (p jsonPatch) Empty() bool {
13+
func (p JsonPatch) Empty() bool {
1214
return len(p) == 0
1315
}
1416

15-
// jsonOperation is a wrapper to jsondiff.jsonOperation with proper serialization for json and yaml
16-
type jsonOperation struct {
17-
OldValue interface{} `json:"oldValue" yaml:"oldValue"`
18-
Value interface{} `json:"value" yaml:"value"`
19-
Type string `json:"op" yaml:"op"`
20-
From string `json:"from" yaml:"from"`
21-
Path string `json:"path" yaml:"path"`
17+
// JsonOperation is a wrapper to jsondiff.JsonOperation with proper serialization for json and yaml
18+
type JsonOperation struct {
19+
OldValue any `json:"oldValue" yaml:"oldValue"`
20+
Value any `json:"value" yaml:"value"`
21+
Type string `json:"op" yaml:"op"`
22+
From string `json:"from" yaml:"from"`
23+
Path string `json:"path" yaml:"path"`
24+
}
25+
26+
func (op *JsonOperation) String() string {
27+
switch op.Type {
28+
case "add":
29+
return fmt.Sprintf("Added %s with value: '%v'", op.Path, op.Value)
30+
case "remove":
31+
return fmt.Sprintf("Removed %s with value: '%v'", op.Path, op.OldValue)
32+
case "replace":
33+
path := op.Path
34+
if path == "" {
35+
path = "value"
36+
}
37+
return fmt.Sprintf("Modified %s from '%v' to '%v'", path, op.OldValue, op.Value)
38+
default:
39+
return fmt.Sprintf("%s %s", op.Type, op.Path)
40+
}
2241
}
2342

24-
func toJsonPatch(patch jsondiff.Patch) jsonPatch {
25-
result := make(jsonPatch, len(patch))
43+
func toJsonPatch(patch jsondiff.Patch) JsonPatch {
44+
result := make(JsonPatch, len(patch))
2645
for i, op := range patch {
2746
result[i] = newJsonOperation(op)
2847
}
2948
return result
3049
}
3150

32-
func newJsonOperation(op jsondiff.Operation) *jsonOperation {
33-
return &jsonOperation{
51+
func newJsonOperation(op jsondiff.Operation) *JsonOperation {
52+
return &JsonOperation{
3453
OldValue: op.OldValue,
3554
Value: op.Value,
3655
Type: op.Type,
@@ -39,7 +58,7 @@ func newJsonOperation(op jsondiff.Operation) *jsonOperation {
3958
}
4059
}
4160

42-
func compareJson(source, target interface{}, opts ...jsondiff.Option) (jsonPatch, error) {
61+
func compareJson(source, target interface{}, opts ...jsondiff.Option) (JsonPatch, error) {
4362
patch, err := jsondiff.Compare(source, target, opts...)
4463
if err != nil {
4564
return nil, err

diff/json_diff_test.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package diff_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/require"
7+
"github.com/tufin/oasdiff/diff"
8+
)
9+
10+
func TestJsonOperationString_Add(t *testing.T) {
11+
p := diff.JsonOperation{
12+
OldValue: "old",
13+
Value: "new",
14+
Type: "add",
15+
From: "from",
16+
Path: "path",
17+
}
18+
require.Equal(t, "Added path with value: 'new'", p.String())
19+
}
20+
21+
func TestJsonOperationString_Remove(t *testing.T) {
22+
p := diff.JsonOperation{
23+
OldValue: "old",
24+
Value: "new",
25+
Type: "remove",
26+
From: "from",
27+
Path: "path",
28+
}
29+
require.Equal(t, "Removed path with value: 'old'", p.String())
30+
}
31+
32+
func TestJsonOperationString_Replace(t *testing.T) {
33+
p := diff.JsonOperation{
34+
OldValue: "old",
35+
Value: "new",
36+
Type: "replace",
37+
From: "from",
38+
Path: "path",
39+
}
40+
require.Equal(t, "Modified path from 'old' to 'new'", p.String())
41+
}
42+
43+
func TestJsonOperationString_ReplaceNoPath(t *testing.T) {
44+
p := diff.JsonOperation{
45+
OldValue: "old",
46+
Value: "new",
47+
Type: "replace",
48+
From: "from",
49+
Path: "",
50+
}
51+
require.Equal(t, "Modified value from 'old' to 'new'", p.String())
52+
}
53+
54+
func TestJsonOperationString_Unknown(t *testing.T) {
55+
p := diff.JsonOperation{
56+
OldValue: "old",
57+
Value: "new",
58+
Type: "unknown",
59+
From: "from",
60+
Path: "path",
61+
}
62+
require.Equal(t, "unknown path", p.String())
63+
}

diff/modified_interfaces.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package diff
22

33
// ModifiedInterfaces is map of interface names to their respective diffs
4-
type ModifiedInterfaces map[string]jsonPatch
4+
type ModifiedInterfaces map[string]JsonPatch
55

66
// Empty indicates whether a change was found in this element
77
func (modifiedInterfaces ModifiedInterfaces) Empty() bool {

report/example_test.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,19 @@ func ExampleGetTextReportAsString() {
4343
// ### Modified Endpoints: 4
4444
// -------------------------
4545
// GET /api/{domain}/{project}/badges/security-score
46+
// - Extensions changed
47+
// - Deleted extension: x-extension-test
48+
// - Tags changed from 'security' to ''
49+
// - OperationID changed from 'GetSecurityScores' to 'GetSecurityScore'
4650
// - Deleted query param: filter
4751
// - Deleted header param: user
4852
// - Deleted cookie param: test
4953
// - Modified query param: image
54+
// - Extensions changed
55+
// - New extension: x-extension-test
5056
// - Schema changed
57+
// - Extensions changed
58+
// - Deleted extension: x-extension-test
5159
// - Property 'Not' changed
5260
// - Schema added
5361
// - Type changed from 'string' to ''
@@ -76,9 +84,14 @@ func ExampleGetTextReportAsString() {
7684
// - New enum values: [test1]
7785
// - Responses changed
7886
// - Modified response: default
87+
// - Extensions changed
88+
// - New extension: x-extension-test
89+
// - New extension: x-test
7990
// - Description changed from 'Tufin1' to 'Tufin'
8091
// - Headers changed
8192
// - Modified header: X-RateLimit-Limit
93+
// - Extensions changed
94+
// - New extension: x-test
8295
// - Description changed from 'Request limit per hour.' to 'Request limit per min.'
8396
// - Servers changed
8497
// - New server: https://api.oasdiff.com
@@ -94,6 +107,13 @@ func ExampleGetTextReportAsString() {
94107
// POST /subscribe
95108
// - Callbacks changed
96109
//
110+
// Other Changes
111+
// -------------
112+
// Extensions changed
113+
// - Deleted extension: x-extension-test
114+
// - Modified extension: x-extension-test2
115+
// - Modified value from 'go' to 'nogo'
116+
//
97117
// Security Requirements changed
98118
// - Deleted security requirements: bearerAuth
99119
//
@@ -141,13 +161,30 @@ func ExampleGetHTMLReportAsString() {
141161
// <hr>
142162
// <p>GET /api/{domain}/{project}/badges/security-score</p>
143163
// <ul>
164+
// <li>Extensions changed
165+
// <ul>
166+
// <li>Deleted extension: x-extension-test</li>
167+
// </ul>
168+
// </li>
169+
// <li>Tags changed from 'security' to ''</li>
170+
// <li>OperationID changed from 'GetSecurityScores' to 'GetSecurityScore'</li>
144171
// <li>Deleted query param: filter</li>
145172
// <li>Deleted header param: user</li>
146173
// <li>Deleted cookie param: test</li>
147174
// <li>Modified query param: image
148175
// <ul>
176+
// <li>Extensions changed
177+
// <ul>
178+
// <li>New extension: x-extension-test</li>
179+
// </ul>
180+
// </li>
149181
// <li>Schema changed
150182
// <ul>
183+
// <li>Extensions changed
184+
// <ul>
185+
// <li>Deleted extension: x-extension-test</li>
186+
// </ul>
187+
// </li>
151188
// <li>Property 'Not' changed
152189
// <ul>
153190
// <li>Schema added</li>
@@ -207,11 +244,22 @@ func ExampleGetHTMLReportAsString() {
207244
// <ul>
208245
// <li>Modified response: default
209246
// <ul>
247+
// <li>Extensions changed
248+
// <ul>
249+
// <li>New extension: x-extension-test</li>
250+
// <li>New extension: x-test</li>
251+
// </ul>
252+
// </li>
210253
// <li>Description changed from 'Tufin1' to 'Tufin'</li>
211254
// <li>Headers changed
212255
// <ul>
213256
// <li>Modified header: X-RateLimit-Limit
214257
// <ul>
258+
// <li>Extensions changed
259+
// <ul>
260+
// <li>New extension: x-test</li>
261+
// </ul>
262+
// </li>
215263
// <li>Description changed from 'Request limit per hour.' to 'Request limit per min.'</li>
216264
// </ul>
217265
// </li>
@@ -246,6 +294,16 @@ func ExampleGetHTMLReportAsString() {
246294
// <ul>
247295
// <li>Callbacks changed</li>
248296
// </ul>
297+
// <h2 id="other-changes">Other Changes</h2>
298+
// <p>Extensions changed</p>
299+
// <ul>
300+
// <li>Deleted extension: x-extension-test</li>
301+
// <li>Modified extension: x-extension-test2
302+
// <ul>
303+
// <li>Modified value from 'go' to 'nogo'</li>
304+
// </ul>
305+
// </li>
306+
// </ul>
249307
// <p>Security Requirements changed</p>
250308
// <ul>
251309
// <li>Deleted security requirements: bearerAuth</li>

0 commit comments

Comments
 (0)