bumping google.golang.org/api b52e40b...ee5c9cc: > ee5c9cc chore(main): release 0.159.0 (# 2378) > 55b0516 fix(transport): relax universe checks (# 2376) > a8d9414 feat(all): auto-regenerate discovery clients (# 2377) > 68b1bc1 chore(main): release 0.158.0 (# 2360) > df17254 fix(transport/grpc): add universe domain verification (# 2375) > b21a1fa fix(internal): support internaloption.WithDefaultUniverseDomain (# 2373) > ddb3a12 chore(google-api-go-generator): replace literal with const (# 2363) > d266978 feat(all): auto-regenerate discovery clients (# 2374) > 73fc7fd fix(transport): not enable s2a when there is endpoint override (# 2368) > 2d69d97 feat(all): auto-regenerate discovery clients (# 2372) > 45c097f feat(all): auto-regenerate discovery clients (# 2369) > addc18c chore(all): update module github.com/google/go-github/v52 to v58 (# 2351) > a4e39d8 chore(all): update all to v0.47.0 (# 2367) > e0db6a5 feat(all): auto-regenerate discovery clients (# 2366) > f40db7f feat(all): auto-regenerate discovery clients (# 2365) > 69626e3 feat(transport): add universe domain support (# 2355) > 6c3b622 feat(all): auto-regenerate discovery clients (# 2361) > 6ef1144 feat(impersonate): add universe domain support (# 2296) > 6e77ef2 chore(main): release 0.157.0 (# 2346) > 72a8ffd feat(all): auto-regenerate discovery clients (# 2358) > 74a1558 docs(option): update WithDefaultEndpointTemplate docs (# 2356) > 135da01 chore(all): update all to a9fa171 (# 2350) > 0d002f9 feat(all): auto-regenerate discovery clients (# 2354) > da330c2 feat(all): auto-regenerate discovery clients (# 2353) > 5bf46ee feat(all): auto-regenerate discovery clients (# 2352) > 3bf8f4f feat(all): auto-regenerate discovery clients (# 2349) > 763c331 feat(all): auto-regenerate discovery clients (# 2348) > c3e43a1 feat(all): auto-regenerate discovery clients (# 2345) > d016573 chore(main): release 0.156.0 (# 2333) > 05de776 feat(all): auto-regenerate discovery clients (# 2344) > 811e925 feat(all): auto-regenerate discovery clients (# 2343) > 9e45101 feat(google-api-go-generator): add universe domain support (# 2335) > 3f90b98 feat(all): auto-regenerate discovery clients (# 2341) > 9745014 test: fix overflow (# 2342) > 3f8b548 chore(all): update all (# 2338) > c8905be chore(deps): bump github.com/cloudflare/circl from 1.3.3 to 1.3.7 in /internal/kokoro/discogen (# 2340) > d008b6e feat(all): auto-regenerate discovery clients (# 2339) > ceefb9b feat(all): auto-regenerate discovery clients (# 2337) > bd4dad1 feat(all): auto-regenerate discovery clients (# 2336) > 014a8e0 feat(all): auto-regenerate discovery clients (# 2332) bumping knative.dev/hack f3f03ac...ab9b690: > ab9b690 Don't hardcode serving as the repo when setting highest semver (# 361) > 45dcf10 Update community files (# 360) > 40f0ac2 Update community files (# 359) bumping github.com/google/uuid 4d47f8e...0f11ee6: > 0f11ee6 chore(master): release 1.6.0 (# 151) > 16939da chore(tests): add strict monotonicity test case for uuid v7. (# 154) > 016b199 fix: fix typo in version 7 uuid documentation (# 153) > 1d8b6ea ci: set token permissions to github workflows (# 143) > a2b2b32 fix: Monotonicity in UUIDv7 (# 150) > c58770e feat: add Max UUID constant (# 149) bumping knative.dev/pkg b488e7b...d34ca03: > d34ca03 Update knative.dev/hack to latest main (# 2949) > 91c6ec8 Bump google.golang.org/api from 0.157.0 to 0.159.0 (# 2946) > 6d59538 Bump github.com/evanphx/json-patch/v5 from 5.8.1 to 5.9.0 (# 2945) > 6eb53f5 Bump github.com/google/uuid from 1.5.0 to 1.6.0 (# 2944) > 2b8687a upgrade to latest dependencies (# 2943) > b42fab9 Update community files (# 2942) > 3f7ce63 Bump google.golang.org/api from 0.155.0 to 0.157.0 (# 2941) > 2a92e9d Bump github.com/evanphx/json-patch/v5 from 5.8.0 to 5.8.1 (# 2940) > 455683d Update community files (# 2939) bumping google.golang.org/genproto/googleapis/api 989df2b...50ed04b: > 50ed04b chore(all): update all to v4 (# 1076) > 0d6446b chore(all): update all (# 1075) > 995d672 chore(all): update all (# 1073) bumping google.golang.org/genproto 989df2b...50ed04b: > 50ed04b chore(all): update all to v4 (# 1076) > 0d6446b chore(all): update all (# 1075) > 995d672 chore(all): update all (# 1073) bumping github.com/go-logr/logr 8adefbe...dcdc3f2: > dcdc3f2 slogr: fix unintended API break in v0.8.0 (# 253) > 5d88f52 funcr: Add LogInfoLevel Option to skip logging level in the info log (# 240) > 177005d build(deps): bump actions/upload-artifact from 3.1.3 to 4.0.0 > e7f489a build(deps): bump github/codeql-action from 2.22.9 to 3.22.11 > cf56c3b build(deps): bump actions/setup-go from 4 to 5 > 2ad296e build(deps): bump github/codeql-action from 2.22.8 to 2.22.9 > d55b4e2 Merge pull request # 241 from thockin/master > c589653 Merge pull request # 245 from thockin/sloghandler_empty_groups > 98ee9d9 Clean up slog testing and restore coverage > 006d752 Merge pull request # 246 from thockin/slog_context_tests > b01bad7 sloghandler: unnamed groups should be inlined > b228ba8 Break examples to new file > 5153ab2 unit tests with full SlogSink mock implementation > 2665157 Add tests for context with slog > 6432877 Add benchmarks for slogSink > 58f101e Fix bug in slog support carrying the wrong sink > f558531 Put slog tests in a helper, move funcr test > 6151b2f support a slog.Logger pointer in a context > 83dbe72 Fix some lint > 1fffd07 move slogr into main package > b5e7d9f funcr: Be consistent about quoted > 41d36ee build(deps): bump github/codeql-action from 2.22.7 to 2.22.8 > 44c6ac8 funcr: Be consistent about colons > f36813a build(deps): bump github/codeql-action from 2.22.5 to 2.22.7 > 955d2aa funcr: Be consistent about commas > 24eb27c build(deps): bump actions/github-script from 6.4.1 to 7.0.1 > 8221825 Add SlogSink support to funcr > 5b79d78 Merge pull request # 233 from go-logr/dependabot/github_actions/github/codeql-action-2.22.5 > d95f9b6 Get rid of testSlogSink > 424fad7 Merge pull request # 232 from go-logr/dependabot/github_actions/ossf/scorecard-action-2.3.1 > e602c1d build(deps): bump github/codeql-action from 2.22.4 to 2.22.5 > cdb930d Minor cleanups in slogr_test (readability) > 64618df build(deps): bump ossf/scorecard-action from 2.3.0 to 2.3.1 Signed-off-by: Knative Automation <automation@knative.team> |
||
---|---|---|
.. | ||
v5 | ||
.gitignore | ||
LICENSE | ||
README.md | ||
errors.go | ||
merge.go | ||
patch.go |
README.md
JSON-Patch
jsonpatch
is a library which provides functionality for both applying
RFC6902 JSON patches against documents, as
well as for calculating & applying RFC7396 JSON merge patches.
Get It!
Latest and greatest:
go get -u github.com/evanphx/json-patch/v5
Stable Versions:
- Version 5:
go get -u gopkg.in/evanphx/json-patch.v5
- Version 4:
go get -u gopkg.in/evanphx/json-patch.v4
(previous versions below v3
are unavailable)
Use It!
- Create and apply a merge patch
- Create and apply a JSON Patch
- Comparing JSON documents
- Combine merge patches
Configuration
-
There is a global configuration variable
jsonpatch.SupportNegativeIndices
. This defaults totrue
and enables the non-standard practice of allowing negative indices to mean indices starting at the end of an array. This functionality can be disabled by settingjsonpatch.SupportNegativeIndices = false
. -
There is a global configuration variable
jsonpatch.AccumulatedCopySizeLimit
, which limits the total size increase in bytes caused by "copy" operations in a patch. It defaults to 0, which means there is no limit.
These global variables control the behavior of jsonpatch.Apply
.
An alternative to jsonpatch.Apply
is jsonpatch.ApplyWithOptions
whose behavior
is controlled by an options
parameter of type *jsonpatch.ApplyOptions
.
Structure jsonpatch.ApplyOptions
includes the configuration options above
and adds two new options: AllowMissingPathOnRemove
and EnsurePathExistsOnAdd
.
When AllowMissingPathOnRemove
is set to true
, jsonpatch.ApplyWithOptions
will ignore
remove
operations whose path
points to a non-existent location in the JSON document.
AllowMissingPathOnRemove
defaults to false
which will lead to jsonpatch.ApplyWithOptions
returning an error when hitting a missing path
on remove
.
When EnsurePathExistsOnAdd
is set to true
, jsonpatch.ApplyWithOptions
will make sure
that add
operations produce all the path
elements that are missing from the target object.
Use jsonpatch.NewApplyOptions
to create an instance of jsonpatch.ApplyOptions
whose values are populated from the global configuration variables.
Create and apply a merge patch
Given both an original JSON document and a modified JSON document, you can create a Merge Patch document.
It can describe the changes needed to convert from the original to the modified JSON document.
Once you have a merge patch, you can apply it to other JSON documents using the
jsonpatch.MergePatch(document, patch)
function.
package main
import (
"fmt"
jsonpatch "github.com/evanphx/json-patch"
)
func main() {
// Let's create a merge patch from these two documents...
original := []byte(`{"name": "John", "age": 24, "height": 3.21}`)
target := []byte(`{"name": "Jane", "age": 24}`)
patch, err := jsonpatch.CreateMergePatch(original, target)
if err != nil {
panic(err)
}
// Now lets apply the patch against a different JSON document...
alternative := []byte(`{"name": "Tina", "age": 28, "height": 3.75}`)
modifiedAlternative, err := jsonpatch.MergePatch(alternative, patch)
fmt.Printf("patch document: %s\n", patch)
fmt.Printf("updated alternative doc: %s\n", modifiedAlternative)
}
When ran, you get the following output:
$ go run main.go
patch document: {"height":null,"name":"Jane"}
updated alternative doc: {"age":28,"name":"Jane"}
Create and apply a JSON Patch
You can create patch objects using DecodePatch([]byte)
, which can then
be applied against JSON documents.
The following is an example of creating a patch from two operations, and applying it against a JSON document.
package main
import (
"fmt"
jsonpatch "github.com/evanphx/json-patch"
)
func main() {
original := []byte(`{"name": "John", "age": 24, "height": 3.21}`)
patchJSON := []byte(`[
{"op": "replace", "path": "/name", "value": "Jane"},
{"op": "remove", "path": "/height"}
]`)
patch, err := jsonpatch.DecodePatch(patchJSON)
if err != nil {
panic(err)
}
modified, err := patch.Apply(original)
if err != nil {
panic(err)
}
fmt.Printf("Original document: %s\n", original)
fmt.Printf("Modified document: %s\n", modified)
}
When ran, you get the following output:
$ go run main.go
Original document: {"name": "John", "age": 24, "height": 3.21}
Modified document: {"age":24,"name":"Jane"}
Comparing JSON documents
Due to potential whitespace and ordering differences, one cannot simply compare JSON strings or byte-arrays directly.
As such, you can instead use jsonpatch.Equal(document1, document2)
to
determine if two JSON documents are structurally equal. This ignores
whitespace differences, and key-value ordering.
package main
import (
"fmt"
jsonpatch "github.com/evanphx/json-patch"
)
func main() {
original := []byte(`{"name": "John", "age": 24, "height": 3.21}`)
similar := []byte(`
{
"age": 24,
"height": 3.21,
"name": "John"
}
`)
different := []byte(`{"name": "Jane", "age": 20, "height": 3.37}`)
if jsonpatch.Equal(original, similar) {
fmt.Println(`"original" is structurally equal to "similar"`)
}
if !jsonpatch.Equal(original, different) {
fmt.Println(`"original" is _not_ structurally equal to "different"`)
}
}
When ran, you get the following output:
$ go run main.go
"original" is structurally equal to "similar"
"original" is _not_ structurally equal to "different"
Combine merge patches
Given two JSON merge patch documents, it is possible to combine them into a single merge patch which can describe both set of changes.
The resulting merge patch can be used such that applying it results in a document structurally similar as merging each merge patch to the document in succession.
package main
import (
"fmt"
jsonpatch "github.com/evanphx/json-patch"
)
func main() {
original := []byte(`{"name": "John", "age": 24, "height": 3.21}`)
nameAndHeight := []byte(`{"height":null,"name":"Jane"}`)
ageAndEyes := []byte(`{"age":4.23,"eyes":"blue"}`)
// Let's combine these merge patch documents...
combinedPatch, err := jsonpatch.MergeMergePatches(nameAndHeight, ageAndEyes)
if err != nil {
panic(err)
}
// Apply each patch individual against the original document
withoutCombinedPatch, err := jsonpatch.MergePatch(original, nameAndHeight)
if err != nil {
panic(err)
}
withoutCombinedPatch, err = jsonpatch.MergePatch(withoutCombinedPatch, ageAndEyes)
if err != nil {
panic(err)
}
// Apply the combined patch against the original document
withCombinedPatch, err := jsonpatch.MergePatch(original, combinedPatch)
if err != nil {
panic(err)
}
// Do both result in the same thing? They should!
if jsonpatch.Equal(withCombinedPatch, withoutCombinedPatch) {
fmt.Println("Both JSON documents are structurally the same!")
}
fmt.Printf("combined merge patch: %s", combinedPatch)
}
When ran, you get the following output:
$ go run main.go
Both JSON documents are structurally the same!
combined merge patch: {"age":4.23,"eyes":"blue","height":null,"name":"Jane"}
CLI for comparing JSON documents
You can install the commandline program json-patch
.
This program can take multiple JSON patch documents as arguments,
and fed a JSON document from stdin
. It will apply the patch(es) against
the document and output the modified doc.
patch.1.json
[
{"op": "replace", "path": "/name", "value": "Jane"},
{"op": "remove", "path": "/height"}
]
patch.2.json
[
{"op": "add", "path": "/address", "value": "123 Main St"},
{"op": "replace", "path": "/age", "value": "21"}
]
document.json
{
"name": "John",
"age": 24,
"height": 3.21
}
You can then run:
$ go install github.com/evanphx/json-patch/cmd/json-patch
$ cat document.json | json-patch -p patch.1.json -p patch.2.json
{"address":"123 Main St","age":"21","name":"Jane"}
Help It!
Contributions are welcomed! Leave an issue or create a PR.
Before creating a pull request, we'd ask that you make sure tests are passing and that you have added new tests when applicable.
Contributors can run tests using:
go test -cover ./...
Builds for pull requests are tested automatically using TravisCI.