-
Notifications
You must be signed in to change notification settings - Fork 122
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Expose JSON Patch operations as public API #1089
Conversation
4ce8617
to
820316f
Compare
/** | ||
* Returns the name of the repository. | ||
*/ | ||
public String repositoryName() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The getters will be useful when logging.
if (Iterables.isEmpty(changes)) { | ||
return false; | ||
} | ||
// JsonPatch operations its own validation for the changes so we don't need to validate them here. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
allow an empty message JSON patch because test or testAbsent do not have changes
Question) Is this logic so that users can use json patches that only contain test
type?
If so, was there a request to let users apply json patches solely comprising of test operations? I imagined that this operation exists only to be used in conjunction with other mutating patches
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't think of a case where users use only test
. It was originally added for removeIfExists
which removes a node only if it exists. If a node is absent, the change for removeIfExists
will be empty.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see.
If a node is absent, the change for removeIfExists will be empty.
So in this case, I understood your proposal is that an extra commit is added. Am I understanding correctly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If JSON patch operations do not create a change, an empty commit is allowed and the request is returned as success. No extra commit will be added.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No extra commit will be added.
Tested at JsonPatchOperationIntegrationTest.removeIfExists
and it seems like the extra commit is added.
before the second commit
user@AL02437565 bar % git cat-file --batch-check --batch-all-objects
0ffe3ffe89a256411408733924396c73749a0da2 commit 307
27730a65b30896185d4fd495790b301e657cb70c commit 309
3b734aff447e0db5994659b62e2c62bc9f69c7a8 tree 34
4b825dc642cb6eb9a060e54bf8d69288fbee4904 tree 0
560674f7d227411ca65c21329bbb9ce5b0fe8dd9 blob 7
73a5d70e33e32e09271e19a98a3326573331d88d blob 13
893c0f344db68915ae53c4fbce76529ebe445c28 commit 276
8efc8a3bfa377804232a6fd4dc8af7870d2623d9 tree 34
user@AL02437565 bar % git cat-file --batch-check --batch-all-objects
after the second commit
0ffe3ffe89a256411408733924396c73749a0da2 commit 307
27730a65b30896185d4fd495790b301e657cb70c commit 309
3b734aff447e0db5994659b62e2c62bc9f69c7a8 tree 34
4502bce9e89208c2d88834d590e67a31cdedff78 commit 315
4b825dc642cb6eb9a060e54bf8d69288fbee4904 tree 0
560674f7d227411ca65c21329bbb9ce5b0fe8dd9 blob 7
73a5d70e33e32e09271e19a98a3326573331d88d blob 13
893c0f344db68915ae53c4fbce76529ebe445c28 commit 276
8efc8a3bfa377804232a6fd4dc8af7870d2623d9 tree 34
user@AL02437565 bar % git cat-file -p 4502bce9e89208c2d88834d590e67a31cdedff78
tree 3b734aff447e0db5994659b62e2c62bc9f69c7a8
parent 27730a65b30896185d4fd495790b301e657cb70c
author admin <[email protected]> 1737441026 +0000
committer admin <[email protected]> 1737441026 +0000
{
"summary" : "remove a again",
"detail" : "",
"markup" : "plaintext",
"revision" : "4"
}% user@AL02437565 bar %
Or did you mean something else by 'no extra commit is added'?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An empty commit means pushing a commit without any object.
We shouldn't add an empty commit when removeIfExists
is solely used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tested at JsonPatchOperationIntegrationTest.removeIfExists and it seems like the extra commit is added.
Good point. Let me fix it not to commit an empty object.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good all in all. 👍
common/src/main/java/com/linecorp/centraldogma/common/jsonpatch/DualPathOperation.java
Show resolved
Hide resolved
common/src/main/java/com/linecorp/centraldogma/common/jsonpatch/JsonPatchOperation.java
Outdated
Show resolved
Hide resolved
.../com/linecorp/centraldogma/server/internal/storage/repository/git/DefaultChangesApplier.java
Show resolved
Hide resolved
if (Iterables.isEmpty(changes)) { | ||
return false; | ||
} | ||
// JsonPatch operations its own validation for the changes so we don't need to validate them here. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An empty commit means pushing a commit without any object.
We shouldn't add an empty commit when removeIfExists
is solely used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great. 👍 👍 👍
...ain/java/com/linecorp/centraldogma/server/internal/storage/repository/git/GitRepository.java
Outdated
Show resolved
Hide resolved
Please, fix the conflict when you get a chance. 😉 |
Done |
static Change<JsonNode> ofJsonPatch(String path, Iterable<? extends JsonPatchOperation> jsonPatches) { | ||
requireNonNull(path, "path"); | ||
requireNonNull(jsonPatches, "jsonPatches"); | ||
return new DefaultChange<>(path, ChangeType.APPLY_JSON_PATCH, | ||
JsonPatchOperation.asJsonArray(jsonPatches)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reject when jsonPatches
is empty?
final PushResult result1 = repository.commit("remove a again", change) | ||
.push() | ||
.join(); | ||
// Should not increase the revision if the path is absent and the history must be the same. | ||
assertThat(result1.revision()).isEqualTo(result0.revision()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we expect a RedundantChangeException
instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RedundantChangeException
is a good approach, but since it is a conditional operator, I thought handling it as a no-op when the path is absent would align better with the existing contract rather than throwing an exception.
Lines 35 to 36 in 1cafcd1
* <p>This operation only takes one pointer ({@code path}) as an argument. Unlike, {@link RemoveOperation}, it | |
* does not throw an error if no JSON value exists at that pointer.</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I discussed this internally with @trustin and agreed that raising RedundantChangeException
on the empty commit for all commits is more consistent behavior. Some users might get confused if RedundantChangeException
is not raised when no commit is made.
If allowing an empty commit is necessary, we can consider adding it as a separate option.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, @ikhoon!
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1089 +/- ##
============================================
+ Coverage 70.07% 70.40% +0.32%
- Complexity 4486 4550 +64
============================================
Files 453 455 +2
Lines 18161 18544 +383
Branches 2008 2037 +29
============================================
+ Hits 12727 13056 +329
- Misses 4345 4392 +47
- Partials 1089 1096 +7 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
👍 |
Motivation:
JSON Patch syntax is not easy to write in string. An API will prevent users from writing raw operations in string and help to build JSON Patch operations type-safely.
Modifications:
common.jsonpatch
frominternal.jsonpatch
.Change.ofJsonPatch()
to create JSON patch theJsonPatchOperation
s.JsonPatchOperation
.JsonPatchConflictException
andTextPatchConflitException
to distinguish exceptions easily and provide a detailed message.GitRepository
to allow an empty message JSON patch becausetest
ortestAbsent
do not have changes.Result:
JsonPatch
as public API #1088JsonPatchOperation
.The operations above can be used to create a change and push to a Central Dogma server.