-
Notifications
You must be signed in to change notification settings - Fork 420
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
JSONPath Support for TriggerBindings #241
Conversation
The following is the coverage report on pkg/.
|
The following is the coverage report on pkg/.
|
The following is the coverage report on pkg/.
|
The following is the coverage report on pkg/.
|
The following is the coverage report on pkg/.
|
pkg/template/jsonpath_test.go
Outdated
tests := []struct { | ||
name string | ||
expr string | ||
in string |
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.
Instead of encoding the object body to a string then unmarshalling it out, would it be easier to make this interface{} and set the fields as maps?
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.
yeah, don't have a strong opinion on this -> might be a bit more verbose for the array and objects that contain other embedded objects?
name: "null values", | ||
in: objectBody, | ||
expr: "$(body.null)", | ||
want: "null", |
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.
Is this WAI? Even though the payload says null
we should probably make a distinction between null
and "null"
. I say either default to ""
or have ParseJSONPath return *string
so we can represent this nil value (my guess is ""
is probably sufficient)
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.
Yeah, so I went back and forth on this a few times before settling on "null". I agree that if we were talking about return go values, the correct way should be *string
. However, for our use case here (i.e. concatenating the json values in string in the trigger templates), that would result in the string <nil>
. If we use "" to represent the printable value of null
, we have no way to differentiate between null
and the empty string "".
The "null"
and null
collision is unfortunate though I think this is the least bad way at the moment. Also, this issue is only valid if the JSONPath selects a field whose value is null
. If the selection is an object or an array which contains both the string null as well as a null value, we get the following: {"stringNull":"null","nullValue":null}
The following is the coverage report on pkg/.
|
The following is the coverage report on pkg/.
|
The following is the coverage report on pkg/.
|
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.
My biggest overall piece of feedback is that there are some new functions added which could benefit from unit tests. I'm sure we have some coverage via Test_NewResources
, and i can see that you want to break that up later on, but in the meantime i think it's still worth adding unit tests for the new functions right away (and its easier to tell what the expected behaviour is in each function, as well as what's covered and what isnt) <-- i think mostly you've done a great job, e.g. unit tests for ParseJSONPath
but there are couple of functions which i think could also use tests which you probably skipped b/c they are unexported, and i think many of the functions (e.g. relaxedJSONPathExpression) are significant enough to actually be exported and have their own tests
Other than that I think I've just got nitpicks! Overall looks great :D
/approve
And definitely we want to make sure we squash some of these commits before we merge so:
/hold
docs/triggerbindings.md
Outdated
`\$\(header(\.[[:alnum:]_\-]+)?\)` | ||
TriggerBindings can access values from the HTTP JSON body and the headers using | ||
JSONPath expressions. The expressions have to be wrapped in `$()` but can omit | ||
the curly braces `{}` and the leading `.`. |
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.
taking a quick look online, it seems to me like most examples for jsonpath don't include {}
anyway? e.g. https://support.smartbear.com/alertsite/docs/monitors/api/endpoint/jsonpath.html and this json path expression tester: https://jsonpath.curiousconcept.com/
so i'm wondering if a) we need to say this at all or if b) this b/c of the specific version of jsonpath we're using, in which case maybe this sentence could explain a bit more with a link, e.g. something like "We are using jsonpath version blah blah blah, and it expects expressions to be wrapped in {}
, however we do not require {}
in addition to $()
though it can be 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.
https://kubernetes.io/docs/reference/kubectl/jsonpath/ mentions the enclosing {}
though it also says its a JSONPath "template"....maybe we keep things simple and never mention the {}
?
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.
Removed the curly braces from the examples!
} | ||
return resources | ||
} | ||
|
||
// event represents a HTTP event that Triggers processes | ||
type event struct { |
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.
maybe "request" would be a more specific name than "event"?
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.
might be confusing with http.Request
. Also, I like event since we can later add the one-offs such as the $(uid)
to this struct to unify how we do the "templating"
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.
might be confusing with http.Request
it basically is an http.Request tho since it has a header + a body 🤔
I see what you mean about the uid
tho! you're probably right about event
being better in the long run, sgtm :D
|
||
return &event{ | ||
Header: joinedHeaders, | ||
Body: data, |
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 len(body) == 0, what does data end up being?
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.
(maybe we handle this totally fine - but to be sure it might be good to have some unit tests directly for newEvent
?)
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.
Yeah I added that check after verifying the empty body case: https://github.com/tektoncd/triggers/pull/241/files/4fe79f8e2d17b38e31d2d871c983a545cb06db01#diff-8d7c043b29f6a04a92258e1aac64fc2bR44
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 cant see that link anymore - good ol rebasing 😅
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.
🤕
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.
@@ -0,0 +1,158 @@ | |||
package template |
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.
hm do you think there's another name we could use besides "template"? in pipelines we are trying to avoid using the term "templating" for the variable substitution we are doing b/c "template" implies additional functionality we want to avoid adding
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 just realized the type is literally called "trigger template" and this package is probably named after that so just ignore me 🤦♀️
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.
Given the discussion around JSONPath support in pipeline params, it might be worth having a common jsonpath pkg that both pipeline and triggers could use 🤔
Though that's a yak that we should shave another day 😄
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: bobcatfish The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
The current Edit: Looking through the coverage report, there are a few error cases that we should add tests for:
|
cc3b2f6
to
4b3dd7f
Compare
/test pull-tekton-triggers-build-tests |
In tektoncd#178 we decided to support JSONPath syntax for expressions in TriggerBindings. This commit adds functions to support JSONPath using the `k8s.io/client-go/util/jsonpath` library. There are a few deviations from the default behavior of the library: 1. The JSONPath expressions have to be wrapped in the Tekton variable interpolation syntax i.e `$()` : `$(body)`. 2. We support the `RelaxedJSONPathExpresion` syntax used in `kubectl get -o custom-columns`. This means that the curly braces `{}` and the leading dot `.` can be omitted i.e we support both `$(body.key)` as well as `$({.body.key}) 3. We return valid JSON values when the value is a JSON array or map. By default, the library returns a string containing an internal go representation. So, if the JSONPath expression selects `{"a": "b"}`, the library will return `map[a: b]` while we return the valid JSON string i.e `{"a":"b"}` In order to support 3, we have to copy a couple of unexported functions from the library (printResults, and evalToText). Signed-off-by: Dibyo Mukherjee <[email protected]>
ec6a539
to
239553c
Compare
Ok, I think I addressed all the comments! Also, added a few more tests (header values, more relaxed jsonpath expressions etc.) There area a couple of if branches that are hard to test e.g. we only reach there if the unmarshalled value is a Function or a Channel --I don't think any HTTP JSON payload can be unmarshalled to that! Quite a few followups from this:
/hold cancel |
Thanks for all the follow up issues @dibyom !! ❤️ |
This commit switches the expression syntax in TriggerBindings from GJson to JSONPath. Fixes tektoncd#178 Signed-off-by: Dibyo Mukherjee <[email protected]>
/lgtm |
/meow space |
In response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
Changes
There are two commits in this PR. The first commit adds functions for JSONPath and the second one uses those functions to extract values for EventBinding.
Commits:
This commit adds functions to support JSONPath
in
TriggerBindings
using thek8s.io/client-go/util/jsonpath
library.
There are a few deviations from the default behavior of the library:
The JSONPath expressions have to be wrapped in the Tekton variable
interpolation syntax i.e
$()
:$(body)
.We support the
RelaxedJSONPathExpresion
syntax used inkubectl get -o custom-columns
. This means that the curly braces{}
and the leading dot
.
can be omitted i.e we support both$(body.key)
as well as `$({.body.key})
We return valid JSON values when the value is a JSON array or
map. By default, the library returns a string containing an internal
go representation. So, if the JSONPath expression selects
{"a": "b"}
,the library will return
map[a: b]
while we return the valid JSONstring i.e
{"a":"b"}
This commit switches TriggerBinding params to use
JSONPath instead of GJSON.
Part of #178
Submitter Checklist
These are the criteria that every PR should meet, please check them off as you
review them:
See the contribution guide for more details.
Release Notes