-
Notifications
You must be signed in to change notification settings - Fork 263
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
Enable trigger filter to be optional #603
Conversation
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, with some minor cosmetic suggestions.
Thanks !
pkg/kn/commands/trigger/create.go
Outdated
|
||
trigger := constructTrigger(name, namespace, triggerUpdateFlags.Broker, filters) | ||
trigger.Spec.Subscriber = &duckv1.Destination{ | ||
trigger := client_v1alpha1.NewTriggerBuilder(name) |
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.
better call it triggerBuilder
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.
fixed.
pkg/kn/commands/trigger/create.go
Outdated
trigger := constructTrigger(name, namespace, triggerUpdateFlags.Broker, filters) | ||
trigger.Spec.Subscriber = &duckv1.Destination{ | ||
trigger := client_v1alpha1.NewTriggerBuilder(name) | ||
trigger.Namespace(namespace) |
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.
you can chain the calls directly as in
triggerBuilder := NewTriggerBuilder(name).Namespace(...).Broker(....).Subscriber(....)
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.
fixed.
pkg/kn/commands/trigger/create.go
Outdated
trigger := client_v1alpha1.NewTriggerBuilder(name) | ||
trigger.Namespace(namespace) | ||
trigger.Broker(triggerUpdateFlags.Broker) | ||
for k, v := range filters { |
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.
We could conside to add a Filters(map[string]string)
builder method so you could easily do the full chaining (and providers a nicer API for the builder)
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.
fixed.
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, but I have still some nit-picks around the builder API (see below)
pkg/eventing/v1alpha1/client.go
Outdated
@@ -170,7 +170,7 @@ func (b *TriggerBuilder) Broker(broker string) *TriggerBuilder { | |||
return b | |||
} | |||
|
|||
func (b *TriggerBuilder) AddFilter(key, value string) *TriggerBuilder { | |||
func (b *TriggerBuilder) AddSingleFilter(key, value string) *TriggerBuilder { |
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'd suggest to keep AddFilter
and jut add a Filters
method for setting the full field (like for the other methods)
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.
In the latest version, I keep only Filters to add multiple filters.
pkg/eventing/v1alpha1/client.go
Outdated
@@ -198,6 +205,13 @@ func (b *TriggerBuilder) RemoveFilter(key string) *TriggerBuilder { | |||
return b | |||
} | |||
|
|||
func (b *TriggerBuilder) RemoveMultipleFilters(keys []string) *TriggerBuilder { |
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.
Do wee need this ? (and also RemoveFilter). At the end its a builder with a very short lifetime. If you don't want to have something added, just don't add it. IMO, we should only have methods which 'build up' something.
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 remove filter will remove existing filters setting by --filter name-
.
If I need to remove some existing filters, what should I do ? Get the existing map of filters, then remove some keys outside builder, and then set back to builder ?
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 keep only RemoveFilters in the latest version to remove those filters from existing attributes setting by --filter name-
pkg/kn/commands/trigger/update.go
Outdated
for _, k := range removed { | ||
b.RemoveFilter(k) | ||
} | ||
b.Filters(updated).RemoveFilters(removed) |
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.
Sorry, my last nit-pick (promised :). What do you think about:
b.Filters(maputil.RemoveKeysFromMap(updated, removed))
and a maputil.RemoveFrom()
(but maybe in an already existing util package):
func RemoveKeysFromMap(original map[string]string, toRemove []string) map[string]string {
....
}
That way this method could be re-used for other use cases and we don't have to add a Remove
method to a builder.
wdyt ?
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.
never mind. Thank you for the suggestion.
The problem of your suggestion is that I need to get the original value of filters map to remove. I think we want to hide the detail of trigger Spec
by Builder. The value of filters map is Spec.Filter.Attributes
, and Spec.Filter
may be nil at the beginning. If I don't add a method GetFilters()
to Builder, I have to manage the trigger Spec
structure to get the filter. So my code may like below:
var attributes *map[string]string
attributes = nil
if b.Build().Spec.Filter != nil {
attributes = b.Build().Spec.Filter.Attributes
}
b.Filters(maputil.AddAndRemoveFromMap(attributes, updated,removed))
and a method to the util:
func AddAndRemoveFromMap(original *map[string]string, toAdd map[string]string, toRemove []string) map[string]string {
......
}
If I add a GetFilters()
to Builder, it may be much simpler:
b.Filters(maputil.AddAndRemoveFromMap(b.GetFilters(), updated,removed))
but it violates the rule that builder is to build something
.
Do I make sense ? What's your 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.
My suggestion:
// Extract filters directly from original trigger (not builder). Return nil if none.
existing := extractFilters(trigger)
// Use chained util method, so that they can bey reused in different contexts:
// * type StringMap map[string]string
// * func StringMap(map [string]string) StringMap : Just cast or copy to the new type (then call it "NewStringMap")
// * func (m SringMap) Merge(toMerge map[string]string) StringMap
// Keys from the toMerge map override those from the wrapped map
// * func (m map[string]string) RemovKeys(toRemove string[]) for removing the keys of a map. If this no
b.Filters(maputil.StringMap(existing).Merge(updated).Remove(removed))
This would have the benefit:
- Builder is still immutable and write-only
- Reusable string map manipulation functions which can be easily used in different contexts
- Easy to use API (maybe a bit harder to implement but obey one of the principles of good API design: "It should be as easy to use as possible, even when its might harder to implement that parts that are hidden from the user".
Instead of introducing a "StringMap" you could equally cast to the type "StringMap" via existing.(StringMap).Merge(updated).Remove(toRemove)
Does this make sense ?
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. I made a small update to your suggestion.
I used builder as parameter in extractFilters
, not trigger. I don't like to introduce a dependency to knative.dev/eventing/pkg/apis/eventing/v1alpha1
in the update command. If I use trigger as parameter, I have to add this dependency. Here is the definition of extractFilters
func extractFilters(builder *client_v1alpha1.TriggerBuilder) util.StringMap
Is that OK with you?
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 used builder as parameter in
extractFilters
, not trigger. I don't like to introduce a dependency toknative.dev/eventing/pkg/apis/eventing/v1alpha1
in the update command. If I use trigger as parameter, I have to add this dependency. Here is the definition ofextractFilters
Don't we already have the trigger available in this method ? with extractFilters()
I mean just a function within update.go
itself (just holding the loop that you've mentioned). I don't think we should put that into the builder.
I refer to this line:
client/pkg/kn/commands/trigger/update.go
Line 69 in 5c2ac96
trigger, err := eventingClient.GetTrigger(name) |
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.
Ah, you mean a goimport. Good point, but we have the implicit dependency anyway (e.g. via the constructor arg of the builder or the return value). Alternatively you could add the function to client_v1alpha1 package, like client_v1alpha1.ExtractFilters(trigger)
It's better than diving into a builder. E.g. in generally when you call Build()
on a Builder this is considered often to be a final action, so you can't call Build() a second time on the same builder (because it performs some more persisten action). So I would prefer to avoid that in favor of the utility in the client package.
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.
Yes, we already have the implicit dependency. I added a line to goimport in update.go
, and used trigger as input parameter in the latest version. Please review. Thank you.
5c2ac96
to
e2f8966
Compare
pkg/kn/commands/trigger/update.go
Outdated
|
||
func extractFilters(trigger *v1alpha1.Trigger) util.StringMap { | ||
if trigger.Spec.Filter == nil { | ||
return nil |
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.
You should return an empty map here, otherwise you can a panic when you call existing.Merge
and existing
is nil. Its also inconsistent to return different things when Filter == nil
or Filter.Attributes == nil
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.
Changed it in the latest version. Thank you.
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.
minor
pkg/eventing/v1alpha1/client_test.go
Outdated
@@ -142,22 +142,10 @@ func TestTriggerBuilder(t *testing.T) { | |||
assert.DeepEqual(t, expected, b.Build().Spec.Filter) | |||
}) | |||
|
|||
t.Run("update filter with only deletions", func(t *testing.T) { | |||
t.Run("update filter with add and update", func(t *testing.T) { |
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.
this description reads odd... any way to make this clearer?
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.
fixed. Thank you.
The following is the coverage report on the affected files.
|
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 a lot ! Looks good now, and I think we have now also a nice API for builder with allowing to remove parts.
Good work!
/lgtm
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: daisy-ycguo, rhuss 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 |
Proposed Changes