Repository: knative/client
Pull request #560 (2019-12-17 09:39:41)

chore(Changelog): Preparation for v0.11.0

knative-prow-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/knative/client/pull/560#" title="Author self-approved">rhuss</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=knative%2Fclient).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/knative/client/blob/master/OWNERS)~~ [rhuss]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->

Patch:
diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc
index 2a6eb3f1..097f676f 100644
--- a/CHANGELOG.adoc
+++ b/CHANGELOG.adoc
@@ -12,15 +12,83 @@
 |===
 ////
 
-## v0.11.0 (unreleased)
+## v0.11.0 (2019-12-17)
 
 [cols="1,10,3", options="header", width="100%"]
 |===
 | | Description | PR
 
+| 🎁
+| Add `kn trigger update` for updating triggers
+| https://github.com/knative/client/pull/562[#562]
+
+| 🎁
+| Add `kn source cronjob list` for listing CronJob sources
+| https://github.com/knative/client/pull/559[#559]
+
+| 🎁
+| Add `kn source apiserver list` for listing ApiServer sources 
+| https://github.com/knative/client/pull/559[#559]
+
+| 🎁
+| Add `kn trigger list` for listing triggers
+| https://github.com/knative/client/pull/558[#558]
+
+| 🎁
+| Add `kn source apiserver create/delete/update/describe` for managing ApiServer sources
+| https://github.com/knative/client/pull/556[#556]
+
+| 🧽
+| Update to Knative eventing dependency to 0.11.0
+| https://github.com/knative/client/pull/546[#546]
+
+| 🧽
+| Update to Knative serving dependency to 0.11.0
+| https://github.com/knative/client/pull/545[#546]
+
+| 🧽
+| Move cluster URL to `--verbose` for `service describe`
+| https://github.com/knative/client/pull/543[#543]
+
+| 🎁
+| Add `kn source cronjob create/delete/update/describe` for managing CronJob sources
+| https://github.com/knative/client/pull/542[#542]
+
+| 🎁
+| Add `kn trigger create/delete` for managing Eventing triggers
+| https://github.com/knative/client/pull/541[#541]
+
+| 🎁
+| Eventing setup in CI
+| https://github.com/knative/client/pull/538[#538]
+
+| 🎁
+| Add `kn source list-types` for showing available Eventing sources
+| https://github.com/knative/client/pull/536[#536]
+
+| 🐛
+| Update to Go 1.13
+| https://github.com/knative/client/pull/535[#535]
+
+| 🎁
+| Add CI tests for using Kn with Tekton
+| https://github.com/knative/client/pull/528[#528]
+
+| 🧽
+| Update version information for eventing dependencies
+| https://github.com/knative/client/pull/495[#495]
+
 | 🧽
 | Support multiple NAMEs on kn service delete
 | https://github.com/knative/client/pull/492[#492]
+
+| 🧽
+| Add polling fallback for watching on service readiness
+| https://github.com/knative/client/pull/491[#491]
+
+| 🎁
+| Add dependencies for eventing
+| https://github.com/knative/client/pull/470[#470]
 |===
 
 ## v0.10.0 (2019-11-06)
diff --git a/docs/cmd/kn_source_apiserver.md b/docs/cmd/kn_source_apiserver.md
index 29c9fba7..34a65d24 100644
--- a/docs/cmd/kn_source_apiserver.md
+++ b/docs/cmd/kn_source_apiserver.md
@@ -30,5 +30,6 @@ kn source apiserver [flags]
 * [kn source apiserver create](kn_source_apiserver_create.md)	 - Create an ApiServer source.
 * [kn source apiserver delete](kn_source_apiserver_delete.md)	 - Delete an ApiServer source.
 * [kn source apiserver describe](kn_source_apiserver_describe.md)	 - Describe an ApiServer source.
+* [kn source apiserver list](kn_source_apiserver_list.md)	 - List ApiServer sources.
 * [kn source apiserver update](kn_source_apiserver_update.md)	 - Update an ApiServer source.
 
diff --git a/docs/cmd/kn_source_apiserver_create.md b/docs/cmd/kn_source_apiserver_create.md
index ec3efddf..d142ef5a 100644
--- a/docs/cmd/kn_source_apiserver_create.md
+++ b/docs/cmd/kn_source_apiserver_create.md
@@ -22,8 +22,8 @@ kn source apiserver create NAME --resource RESOURCE --service-account ACCOUNTNAM
 
 ```
   -h, --help                     help for create
-      --mode string              The mode the receive adapter controller runs under:, 
-                                 "Ref" sends only the reference to the resource, 
+      --mode string              The mode the receive adapter controller runs under:,
+                                 "Ref" sends only the reference to the resource,
                                  "Resource" send the full resource. (default "Ref")
   -n, --namespace string         Specify the namespace to operate in.
       --resource strings         Comma seperate Kind:APIVersion:isController list, e.g. Event:v1:true.
diff --git a/docs/cmd/kn_source_apiserver_list.md b/docs/cmd/kn_source_apiserver_list.md
new file mode 100644
index 00000000..e90bd299
--- /dev/null
+++ b/docs/cmd/kn_source_apiserver_list.md
@@ -0,0 +1,44 @@
+## kn source apiserver list
+
+List ApiServer sources.
+
+### Synopsis
+
+List ApiServer sources.
+
+```
+kn source apiserver list [flags]
+```
+
+### Examples
+
+```
+
+  # List all ApiServer sources in YAML format
+  kn source apiserver list -o yaml
+```
+
+### Options
+
+```
+  -A, --all-namespaces                If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace.
+      --allow-missing-template-keys   If true, ignore any errors in templates when a field or map key is missing in the template. Only applies to golang and jsonpath output formats. (default true)
+  -h, --help                          help for list
+  -n, --namespace string              Specify the namespace to operate in.
+      --no-headers                    When using the default output format, don't print headers (default: print headers).
+  -o, --output string                 Output format. One of: json|yaml|name|go-template|go-template-file|template|templatefile|jsonpath|jsonpath-file.
+      --template string               Template string or path to template file to use when -o=go-template, -o=go-template-file. The template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview].
+```
+
+### Options inherited from parent commands
+
+```
+      --config string       kn config file (default is $HOME/.kn/config.yaml)
+      --kubeconfig string   kubectl config file (default is $HOME/.kube/config)
+      --log-http            log http traffic
+```
+
+### SEE ALSO
+
+* [kn source apiserver](kn_source_apiserver.md)	 - Kubernetes API Server Event Source command group
+
diff --git a/docs/cmd/kn_source_apiserver_update.md b/docs/cmd/kn_source_apiserver_update.md
index 8b7747a3..168f86f2 100644
--- a/docs/cmd/kn_source_apiserver_update.md
+++ b/docs/cmd/kn_source_apiserver_update.md
@@ -22,8 +22,8 @@ kn source apiserver update NAME --resource RESOURCE --service-account ACCOUNTNAM
 
 ```
   -h, --help                     help for update
-      --mode string              The mode the receive adapter controller runs under:, 
-                                 "Ref" sends only the reference to the resource, 
+      --mode string              The mode the receive adapter controller runs under:,
+                                 "Ref" sends only the reference to the resource,
                                  "Resource" send the full resource. (default "Ref")
   -n, --namespace string         Specify the namespace to operate in.
       --resource strings         Comma seperate Kind:APIVersion:isController list, e.g. Event:v1:true.
diff --git a/docs/cmd/kn_source_cronjob.md b/docs/cmd/kn_source_cronjob.md
index db6d84f8..28d297f1 100644
--- a/docs/cmd/kn_source_cronjob.md
+++ b/docs/cmd/kn_source_cronjob.md
@@ -30,5 +30,6 @@ kn source cronjob [flags]
 * [kn source cronjob create](kn_source_cronjob_create.md)	 - Create a CronJob source.
 * [kn source cronjob delete](kn_source_cronjob_delete.md)	 - Delete a CronJob source.
 * [kn source cronjob describe](kn_source_cronjob_describe.md)	 - Describe a CronJob source.
+* [kn source cronjob list](kn_source_cronjob_list.md)	 - List CronJob sources.
 * [kn source cronjob update](kn_source_cronjob_update.md)	 - Update a CronJob source.
 
diff --git a/docs/cmd/kn_source_cronjob_list.md b/docs/cmd/kn_source_cronjob_list.md
new file mode 100644
index 00000000..a0fe1ab6
--- /dev/null
+++ b/docs/cmd/kn_source_cronjob_list.md
@@ -0,0 +1,44 @@
+## kn source cronjob list
+
+List CronJob sources.
+
+### Synopsis
+
+List CronJob sources.
+
+```
+kn source cronjob list [flags]
+```
+
+### Examples
+
+```
+
+  # List all CronJob sources in YAML format
+  kn source cronjob list -o yaml
+```
+
+### Options
+
+```
+  -A, --all-namespaces                If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace.
+      --allow-missing-template-keys   If true, ignore any errors in templates when a field or map key is missing in the template. Only applies to golang and jsonpath output formats. (default true)
+  -h, --help                          help for list
+  -n, --namespace string              Specify the namespace to operate in.
+      --no-headers                    When using the default output format, don't print headers (default: print headers).
+  -o, --output string                 Output format. One of: json|yaml|name|go-template|go-template-file|template|templatefile|jsonpath|jsonpath-file.
+      --template string               Template string or path to template file to use when -o=go-template, -o=go-template-file. The template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview].
+```
+
+### Options inherited from parent commands
+
+```
+      --config string       kn config file (default is $HOME/.kn/config.yaml)
+      --kubeconfig string   kubectl config file (default is $HOME/.kube/config)
+      --log-http            log http traffic
+```
+
+### SEE ALSO
+
+* [kn source cronjob](kn_source_cronjob.md)	 - CronJob source command group
+
diff --git a/docs/cmd/kn_trigger.md b/docs/cmd/kn_trigger.md
index 77f60d90..b484a4de 100644
--- a/docs/cmd/kn_trigger.md
+++ b/docs/cmd/kn_trigger.md
@@ -31,4 +31,5 @@ kn trigger [flags]
 * [kn trigger delete](kn_trigger_delete.md)	 - Delete a trigger.
 * [kn trigger describe](kn_trigger_describe.md)	 - Describe a trigger.
 * [kn trigger list](kn_trigger_list.md)	 - List available triggers.
+* [kn trigger update](kn_trigger_update.md)	 - Update a trigger
 
diff --git a/docs/cmd/kn_trigger_update.md b/docs/cmd/kn_trigger_update.md
new file mode 100644
index 00000000..4980eef5
--- /dev/null
+++ b/docs/cmd/kn_trigger_update.md
@@ -0,0 +1,49 @@
+## kn trigger update
+
+Update a trigger
+
+### Synopsis
+
+Update a trigger
+
+```
+kn trigger update NAME --filter KEY=VALUE --sink SINK [flags]
+```
+
+### Examples
+
+```
+
+  # Update the filter which key is 'type' to value 'knative.dev.bar' in a trigger 'mytrigger'
+  kn trigger update mytrigger --filter type=knative.dev.bar
+
+  # Remove the filter which key is 'type' from a trigger 'mytrigger' 
+  kn trigger update mytrigger --filter type-
+
+  # Update the sink of a trigger 'mytrigger' to 'svc:new-service'
+  kn trigger update mytrigger --sink svc:new-service
+  
+```
+
+### Options
+
+```
+      --broker string      Name of the Broker which the trigger associates with. (default "default")
+      --filter []string    Key-value pair for exact CloudEvent attribute matching against incoming events, e.g type=dev.knative.foo
+  -h, --help               help for update
+  -n, --namespace string   Specify the namespace to operate in.
+  -s, --sink string        Addressable sink for events
+```
+
+### Options inherited from parent commands
+
+```
+      --config string       kn config file (default is $HOME/.kn/config.yaml)
+      --kubeconfig string   kubectl config file (default is $HOME/.kube/config)
+      --log-http            log http traffic
+```
+
+### SEE ALSO
+
+* [kn trigger](kn_trigger.md)	 - Trigger command group
+
diff --git a/pkg/eventing/sources/v1alpha1/apiserver_client.go b/pkg/eventing/sources/v1alpha1/apiserver_client.go
index 0551690a..3a29ffd2 100644
--- a/pkg/eventing/sources/v1alpha1/apiserver_client.go
+++ b/pkg/eventing/sources/v1alpha1/apiserver_client.go
@@ -37,6 +37,10 @@ type KnAPIServerSourcesClient interface {
 	// Delete an ApiServerSource by name
 	DeleteAPIServerSource(name string) error
 
+	// List ApiServerSource
+	// TODO: Support list configs like in service list
+	ListAPIServerSource() (*v1alpha1.ApiServerSourceList, error)
+
 	// Get namespace for this client
 	Namespace() string
 }
@@ -98,6 +102,35 @@ func (c *apiServerSourcesClient) Namespace() string {
 	return c.namespace
 }
 
+// ListAPIServerSource returns the available ApiServer type sources
+func (c *apiServerSourcesClient) ListAPIServerSource() (*v1alpha1.ApiServerSourceList, error) {
+	sourceList, err := c.client.List(metav1.ListOptions{})
+	if err != nil {
+		return nil, err
+	}
+
+	return updateAPIServerSourceListGVK(sourceList)
+}
+
+func updateAPIServerSourceListGVK(sourceList *v1alpha1.ApiServerSourceList) (*v1alpha1.ApiServerSourceList, error) {
+	sourceListNew := sourceList.DeepCopy()
+	err := updateSourceGVK(sourceListNew)
+	if err != nil {
+		return nil, err
+	}
+
+	sourceListNew.Items = make([]v1alpha1.ApiServerSource, len(sourceList.Items))
+	for idx, source := range sourceList.Items {
+		sourceClone := source.DeepCopy()
+		err := updateSourceGVK(sourceClone)
+		if err != nil {
+			return nil, err
+		}
+		sourceListNew.Items[idx] = *sourceClone
+	}
+	return sourceListNew, nil
+}
+
 // APIServerSourceBuilder is for building the source
 type APIServerSourceBuilder struct {
 	apiServerSource *v1alpha1.ApiServerSource
diff --git a/pkg/eventing/sources/v1alpha1/apiserver_client_mock.go b/pkg/eventing/sources/v1alpha1/apiserver_client_mock.go
index 4ef573e0..21f02131 100644
--- a/pkg/eventing/sources/v1alpha1/apiserver_client_mock.go
+++ b/pkg/eventing/sources/v1alpha1/apiserver_client_mock.go
@@ -103,6 +103,17 @@ func (c *MockKnAPIServerSourceClient) DeleteAPIServerSource(name string) error {
 	return mock.ErrorOrNil(call.Result[0])
 }
 
+// ListAPIServerSource records a call for ListAPIServerSource with the expected error (nil if none)
+func (sr *APIServerSourcesRecorder) ListAPIServerSource(apiJobSourceList *v1alpha1.ApiServerSourceList, err error) {
+	sr.r.Add("ListAPIServerSource", []interface{}{}, []interface{}{apiJobSourceList, err})
+}
+
+// ListAPIServerSource performs a previously recorded action, failing if non has been registered
+func (c *MockKnAPIServerSourceClient) ListAPIServerSource() (*v1alpha1.ApiServerSourceList, error) {
+	call := c.recorder.r.VerifyCall("ListAPIServerSource")
+	return call.Result[0].(*v1alpha1.ApiServerSourceList), mock.ErrorOrNil(call.Result[1])
+}
+
 // Validate validates whether every recorded action has been called
 func (sr *APIServerSourcesRecorder) Validate() {
 	sr.r.CheckThatAllRecordedMethodsHaveBeenCalled()
diff --git a/pkg/eventing/sources/v1alpha1/cronjob_client.go b/pkg/eventing/sources/v1alpha1/cronjob_client.go
index ad32d448..a37aad4d 100644
--- a/pkg/eventing/sources/v1alpha1/cronjob_client.go
+++ b/pkg/eventing/sources/v1alpha1/cronjob_client.go
@@ -17,8 +17,12 @@ package v1alpha1
 import (
 	"fmt"
 
-	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime"
 	"knative.dev/eventing/pkg/apis/sources/v1alpha1"
+
+	"knative.dev/client/pkg/util"
+	"knative.dev/eventing/pkg/client/clientset/versioned/scheme"
 	client_v1alpha1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/sources/v1alpha1"
 	duckv1beta1 "knative.dev/pkg/apis/duck/v1beta1"
 )
@@ -38,6 +42,10 @@ type KnCronJobSourcesClient interface {
 	// Delete a cronjob source by name
 	DeleteCronJobSource(name string) error
 
+	// List CronJob sources
+	// TODO: Support list configs like in service list
+	ListCronJobSource() (*v1alpha1.CronJobSourceList, error)
+
 	// Get namespace for this source
 	Namespace() string
 }
@@ -77,11 +85,44 @@ func (c *cronJobSourcesClient) UpdateCronJobSource(cronjobSource *v1alpha1.CronJ
 }
 
 func (c *cronJobSourcesClient) DeleteCronJobSource(name string) error {
-	return c.client.Delete(name, &meta_v1.DeleteOptions{})
+	return c.client.Delete(name, &metav1.DeleteOptions{})
 }
 
 func (c *cronJobSourcesClient) GetCronJobSource(name string) (*v1alpha1.CronJobSource, error) {
-	return c.client.Get(name, meta_v1.GetOptions{})
+	return c.client.Get(name, metav1.GetOptions{})
+}
+
+// ListCronJobSource returns the available CronJob type sources
+func (c *cronJobSourcesClient) ListCronJobSource() (*v1alpha1.CronJobSourceList, error) {
+	sourceList, err := c.client.List(metav1.ListOptions{})
+	if err != nil {
+		return nil, err
+	}
+
+	return updateCronJobSourceListGVK(sourceList)
+}
+
+func updateCronJobSourceListGVK(sourceList *v1alpha1.CronJobSourceList) (*v1alpha1.CronJobSourceList, error) {
+	sourceListNew := sourceList.DeepCopy()
+	err := updateSourceGVK(sourceListNew)
+	if err != nil {
+		return nil, err
+	}
+
+	sourceListNew.Items = make([]v1alpha1.CronJobSource, len(sourceList.Items))
+	for idx, source := range sourceList.Items {
+		sourceClone := source.DeepCopy()
+		err := updateSourceGVK(sourceClone)
+		if err != nil {
+			return nil, err
+		}
+		sourceListNew.Items[idx] = *sourceClone
+	}
+	return sourceListNew, nil
+}
+
+func updateSourceGVK(obj runtime.Object) error {
+	return util.UpdateGroupVersionKindWithScheme(obj, v1alpha1.SchemeGroupVersion, scheme.Scheme)
 }
 
 // Builder for building up cronjob sources
@@ -92,7 +133,7 @@ type CronJobSourceBuilder struct {
 
 func NewCronJobSourceBuilder(name string) *CronJobSourceBuilder {
 	return &CronJobSourceBuilder{cronjobSource: &v1alpha1.CronJobSource{
-		ObjectMeta: meta_v1.ObjectMeta{
+		ObjectMeta: metav1.ObjectMeta{
 			Name: name,
 		},
 	}}
diff --git a/pkg/eventing/sources/v1alpha1/cronjob_client_mock.go b/pkg/eventing/sources/v1alpha1/cronjob_client_mock.go
index 94610456..74df71ad 100644
--- a/pkg/eventing/sources/v1alpha1/cronjob_client_mock.go
+++ b/pkg/eventing/sources/v1alpha1/cronjob_client_mock.go
@@ -102,6 +102,17 @@ func (c *MockKnCronJobSourceClient) DeleteCronJobSource(name string) error {
 	return mock.ErrorOrNil(call.Result[0])
 }
 
+// ListCronJobSource records a call for ListCronJobSource with the expected error (nil if none)
+func (sr *CronJobSourcesRecorder) ListCronJobSource(cronJobSourceList *v1alpha1.CronJobSourceList, err error) {
+	sr.r.Add("ListCronJobSource", []interface{}{}, []interface{}{cronJobSourceList, err})
+}
+
+// ListCronJobSource performs a previously recorded action, failing if non has been registered
+func (c *MockKnCronJobSourceClient) ListCronJobSource() (*v1alpha1.CronJobSourceList, error) {
+	call := c.recorder.r.VerifyCall("ListCronJobSource")
+	return call.Result[0].(*v1alpha1.CronJobSourceList), mock.ErrorOrNil(call.Result[1])
+}
+
 // Validates validates whether every recorded action has been called
 func (sr *CronJobSourcesRecorder) Validate() {
 	sr.r.CheckThatAllRecordedMethodsHaveBeenCalled()
diff --git a/pkg/eventing/v1alpha1/client.go b/pkg/eventing/v1alpha1/client.go
index aabde5bc..a4296d34 100644
--- a/pkg/eventing/v1alpha1/client.go
+++ b/pkg/eventing/v1alpha1/client.go
@@ -16,12 +16,14 @@ package v1alpha1
 
 import (
 	apis_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
 	kn_errors "knative.dev/client/pkg/errors"
 	"knative.dev/client/pkg/util"
 	"knative.dev/eventing/pkg/apis/eventing/v1alpha1"
 	"knative.dev/eventing/pkg/client/clientset/versioned/scheme"
 	client_v1alpha1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1alpha1"
+	duckv1 "knative.dev/pkg/apis/duck/v1"
 )
 
 const (
@@ -41,6 +43,8 @@ type KnEventingClient interface {
 	GetTrigger(name string) (*v1alpha1.Trigger, error)
 	// ListTrigger returns list of trigger CRDs
 	ListTriggers() (*v1alpha1.TriggerList, error)
+	// UpdateTrigger is used to update an instance of trigger
+	UpdateTrigger(trigger *v1alpha1.Trigger) error
 }
 
 // KnEventingClient is a combination of Sources client interface and namespace
@@ -109,6 +113,15 @@ func (c *knEventingClient) ListTriggers() (*v1alpha1.TriggerList, error) {
 	return triggerListNew, nil
 }
 
+//CreateTrigger is used to create an instance of trigger
+func (c *knEventingClient) UpdateTrigger(trigger *v1alpha1.Trigger) error {
+	trigger, err := c.client.Triggers(c.namespace).Update(trigger)
+	if err != nil {
+		return kn_errors.GetError(err)
+	}
+	return nil
+}
+
 // Return the client's namespace
 func (c *knEventingClient) Namespace() string {
 	return c.namespace
@@ -118,3 +131,70 @@ func (c *knEventingClient) Namespace() string {
 func updateTriggerGvk(obj runtime.Object) error {
 	return util.UpdateGroupVersionKindWithScheme(obj, v1alpha1.SchemeGroupVersion, scheme.Scheme)
 }
+
+// TriggerBuilder is for building the trigger
+type TriggerBuilder struct {
+	trigger *v1alpha1.Trigger
+}
+
+// NewTriggerBuilder for building trigger object
+func NewTriggerBuilder(name string) *TriggerBuilder {
+	return &TriggerBuilder{trigger: &v1alpha1.Trigger{
+		ObjectMeta: meta_v1.ObjectMeta{
+			Name: name,
+		},
+	}}
+}
+
+// NewTriggerBuilderFromExisting for building the object from existing Trigger object
+func NewTriggerBuilderFromExisting(tr *v1alpha1.Trigger) *TriggerBuilder {
+	return &TriggerBuilder{trigger: tr.DeepCopy()}
+}
+
+// Broker to set the broker of trigger object
+func (b *TriggerBuilder) Broker(broker string) *TriggerBuilder {
+	if broker != "" {
+		b.trigger.Spec.Broker = broker
+	}
+	return b
+}
+
+// Filters to set the filters of trigger object
+func (b *TriggerBuilder) Filters(filters map[string]string) *TriggerBuilder {
+	if filters != nil {
+		triggerFilterAttributes := v1alpha1.TriggerFilterAttributes(filters)
+		b.trigger.Spec.Filter = &v1alpha1.TriggerFilter{
+			Attributes: &triggerFilterAttributes,
+		}
+	}
+	return b
+}
+
+// UpdateFilters to update the filters of trigger object
+func (b *TriggerBuilder) UpdateFilters(toUpdate map[string]string, toRemove []string) *TriggerBuilder {
+	if b.trigger.Spec.Filter == nil {
+		b.Filters(toUpdate)
+		return b
+	}
+
+	existing := map[string]string(*b.trigger.Spec.Filter.Attributes)
+	for key, value := range toUpdate {
+		existing[key] = value
+	}
+	for _, key := range toRemove {
+		delete(existing, key)
+	}
+	b.Filters(existing)
+	return b
+}
+
+// Sink to set the subscriber of trigger object
+func (b *TriggerBuilder) Sink(sink *duckv1.Destination) *TriggerBuilder {
+	b.trigger.Spec.Subscriber = sink
+	return b
+}
+
+// Build to return an instance of trigger object
+func (b *TriggerBuilder) Build() *v1alpha1.Trigger {
+	return b.trigger
+}
diff --git a/pkg/eventing/v1alpha1/client_mock.go b/pkg/eventing/v1alpha1/client_mock.go
index 9fcb3b9a..cf3166e0 100644
--- a/pkg/eventing/v1alpha1/client_mock.go
+++ b/pkg/eventing/v1alpha1/client_mock.go
@@ -102,6 +102,17 @@ func (c *MockKnEventingClient) ListTriggers() (*v1alpha1.TriggerList, error) {
 	return call.Result[0].(*v1alpha1.TriggerList), mock.ErrorOrNil(call.Result[1])
 }
 
+// UpdateTrigger records a call for ListTriggers with the expected result and error (nil if none)
+func (sr *EventingRecorder) UpdateTrigger(trigger interface{}, err error) {
+	sr.r.Add("UpdateTrigger", []interface{}{trigger}, []interface{}{err})
+}
+
+// UpdateTrigger performs a previously recorded action
+func (c *MockKnEventingClient) UpdateTrigger(trigger *v1alpha1.Trigger) error {
+	call := c.recorder.r.VerifyCall("UpdateTrigger")
+	return mock.ErrorOrNil(call.Result[0])
+}
+
 // Validate validates whether every recorded action has been called
 func (sr *EventingRecorder) Validate() {
 	sr.r.CheckThatAllRecordedMethodsHaveBeenCalled()
diff --git a/pkg/kn/commands/source/apiserver/apiserver.go b/pkg/kn/commands/source/apiserver/apiserver.go
index 54b9f931..b1a10ee3 100644
--- a/pkg/kn/commands/source/apiserver/apiserver.go
+++ b/pkg/kn/commands/source/apiserver/apiserver.go
@@ -34,6 +34,7 @@ func NewAPIServerCommand(p *commands.KnParams) *cobra.Command {
 	apiServerSourceCmd.AddCommand(NewAPIServerUpdateCommand(p))
 	apiServerSourceCmd.AddCommand(NewAPIServerDescribeCommand(p))
 	apiServerSourceCmd.AddCommand(NewAPIServerDeleteCommand(p))
+	apiServerSourceCmd.AddCommand(NewAPIServerListCommand(p))
 	return apiServerSourceCmd
 }
 
diff --git a/pkg/kn/commands/source/apiserver/flags.go b/pkg/kn/commands/source/apiserver/flags.go
index 4617c2ce..cbc95fc1 100644
--- a/pkg/kn/commands/source/apiserver/flags.go
+++ b/pkg/kn/commands/source/apiserver/flags.go
@@ -15,11 +15,18 @@
 package apiserver
 
 import (
+	"fmt"
+	"sort"
 	"strconv"
 	"strings"
 
 	"github.com/spf13/cobra"
+	"k8s.io/apimachinery/pkg/runtime"
+	"knative.dev/client/pkg/kn/commands"
 	"knative.dev/eventing/pkg/apis/sources/v1alpha1"
+
+	metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1"
+	hprinters "knative.dev/client/pkg/printers"
 )
 
 const (
@@ -77,8 +84,8 @@ func (f *APIServerSourceUpdateFlags) Add(cmd *cobra.Command) {
 	cmd.Flags().StringVar(&f.Mode,
 		"mode",
 		"Ref",
-		`The mode the receive adapter controller runs under:, 
-"Ref" sends only the reference to the resource, 
+		`The mode the receive adapter controller runs under:,
+"Ref" sends only the reference to the resource,
 "Resource" send the full resource.`)
 	cmd.Flags().StringSliceVar(&f.Resources,
 		"resource",
@@ -87,3 +94,108 @@ func (f *APIServerSourceUpdateFlags) Add(cmd *cobra.Command) {
 "APIVersion" and "isControler" can be omitted.
 "APIVersion" is "v1" by default, "isController" is "false" by default.`)
 }
+
+// APIServerSourceListHandlers handles printing human readable table for `kn source apiserver list` command's output
+func APIServerSourceListHandlers(h hprinters.PrintHandler) {
+	sourceColumnDefinitions := []metav1beta1.TableColumnDefinition{
+		{Name: "Namespace", Type: "string", Description: "Namespace of the ApiServer source", Priority: 0},
+		{Name: "Name", Type: "string", Description: "Name of the ApiServer source", Priority: 1},
+		{Name: "Resources", Type: "string", Description: "Event resources configured for the ApiServer source", Priority: 1},
+		{Name: "Sink", Type: "string", Description: "Sink of the ApiServer source", Priority: 1},
+		{Name: "Conditions", Type: "string", Description: "Ready state conditions", Priority: 1},
+		{Name: "Ready", Type: "string", Description: "Ready state of the ApiServer source", Priority: 1},
+		{Name: "Reason", Type: "string", Description: "Reason if state is not Ready", Priority: 1},
+	}
+	h.TableHandler(sourceColumnDefinitions, printSource)
+	h.TableHandler(sourceColumnDefinitions, printSourceList)
+}
+
+// printSource populates a single row of source apiserver list table
+func printSource(source *v1alpha1.ApiServerSource, options hprinters.PrintOptions) ([]metav1beta1.TableRow, error) {
+	row := metav1beta1.TableRow{
+		Object: runtime.RawExtension{Object: source},
+	}
+
+	name := source.Name
+	conditions := commands.ConditionsValue(source.Status.Conditions)
+	ready := commands.ReadyCondition(source.Status.Conditions)
+	reason := strings.TrimSpace(commands.NonReadyConditionReason(source.Status.Conditions))
+	var resources []string
+	for _, resource := range source.Spec.Resources {
+		resources = append(resources, fmt.Sprintf("%s:%s:%s", resource.Kind, resource.APIVersion, strconv.FormatBool(resource.Controller)))
+	}
+
+	var sink string
+	if source.Spec.Sink != nil {
+		if source.Spec.Sink.Ref != nil {
+			if source.Spec.Sink.Ref.Kind == "Service" {
+				sink = fmt.Sprintf("svc:%s", source.Spec.Sink.Ref.Name)
+			} else {
+				sink = fmt.Sprintf("%s:%s", source.Spec.Sink.Ref.Kind, source.Spec.Sink.Ref.Name)
+			}
+		}
+	}
+
+	if options.AllNamespaces {
+		row.Cells = append(row.Cells, source.Namespace)
+	}
+
+	row.Cells = append(row.Cells, name, strings.Join(resources[:], ","), sink, conditions, ready, reason)
+	return []metav1beta1.TableRow{row}, nil
+}
+
+// printSourceList populates the source apiserver list table rows
+func printSourceList(sourceList *v1alpha1.ApiServerSourceList, options hprinters.PrintOptions) ([]metav1beta1.TableRow, error) {
+	if options.AllNamespaces {
+		return printSourceListWithNamespace(sourceList, options)
+	}
+
+	rows := make([]metav1beta1.TableRow, 0, len(sourceList.Items))
+
+	sort.SliceStable(sourceList.Items, func(i, j int) bool {
+		return sourceList.Items[i].GetName() < sourceList.Items[j].GetName()
+	})
+
+	for _, item := range sourceList.Items {
+		row, err := printSource(&item, options)
+		if err != nil {
+			return nil, err
+		}
+
+		rows = append(rows, row...)
+	}
+	return rows, nil
+}
+
+// printSourceListWithNamespace populates the knative service table rows with namespace column
+func printSourceListWithNamespace(sourceList *v1alpha1.ApiServerSourceList, options hprinters.PrintOptions) ([]metav1beta1.TableRow, error) {
+	rows := make([]metav1beta1.TableRow, 0, len(sourceList.Items))
+
+	// temporary slice for sorting services in non-default namespace
+	others := []metav1beta1.TableRow{}
+
+	for _, source := range sourceList.Items {
+		// Fill in with services in `default` namespace at first
+		if source.Namespace == "default" {
+			r, err := printSource(&source, options)
+			if err != nil {
+				return nil, err
+			}
+			rows = append(rows, r...)
+			continue
+		}
+		// put other services in temporary slice
+		r, err := printSource(&source, options)
+		if err != nil {
+			return nil, err
+		}
+		others = append(others, r...)
+	}
+
+	// sort other services list alphabetically by namespace
+	sort.SliceStable(others, func(i, j int) bool {
+		return others[i].Cells[0].(string) < others[j].Cells[0].(string)
+	})
+
+	return append(rows, others...), nil
+}
diff --git a/pkg/kn/commands/source/apiserver/list.go b/pkg/kn/commands/source/apiserver/list.go
new file mode 100644
index 00000000..5bdc81c5
--- /dev/null
+++ b/pkg/kn/commands/source/apiserver/list.go
@@ -0,0 +1,74 @@
+// Copyright © 2019 The Knative Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package apiserver
+
+import (
+	"fmt"
+
+	"github.com/spf13/cobra"
+	"knative.dev/client/pkg/kn/commands"
+	"knative.dev/client/pkg/kn/commands/flags"
+)
+
+// NewAPIServerListCommand is for listing ApiServer source COs
+func NewAPIServerListCommand(p *commands.KnParams) *cobra.Command {
+	listFlags := flags.NewListFlags(APIServerSourceListHandlers)
+
+	listCommand := &cobra.Command{
+		Use:   "list",
+		Short: "List ApiServer sources.",
+		Example: `
+  # List all ApiServer sources in YAML format
+  kn source apiserver list -o yaml`,
+
+		RunE: func(cmd *cobra.Command, args []string) (err error) {
+			// TODO: filter list by given source name
+
+			apiSourceClient, err := newAPIServerSourceClient(p, cmd)
+			if err != nil {
+				return err
+			}
+
+			sourceList, err := apiSourceClient.ListAPIServerSource()
+			if err != nil {
+				return err
+			}
+
+			if len(sourceList.Items) == 0 {
+				fmt.Fprintf(cmd.OutOrStdout(), "No ApiServer source found.\n")
+				return nil
+			}
+
+			if apiSourceClient.Namespace() == "" {
+				listFlags.EnsureWithNamespace()
+			}
+
+			printer, err := listFlags.ToPrinter()
+			if err != nil {
+				return nil
+			}
+
+			err = printer.PrintObj(sourceList, cmd.OutOrStdout())
+			if err != nil {
+				return err
+			}
+
+			return nil
+		},
+	}
+	commands.AddNamespaceFlags(listCommand.Flags(), true)
+	listFlags.AddFlags(listCommand)
+	return listCommand
+}
diff --git a/pkg/kn/commands/source/cronjob/cronjob.go b/pkg/kn/commands/source/cronjob/cronjob.go
index 530935fe..0805557c 100644
--- a/pkg/kn/commands/source/cronjob/cronjob.go
+++ b/pkg/kn/commands/source/cronjob/cronjob.go
@@ -33,6 +33,7 @@ func NewCronJobCommand(p *commands.KnParams) *cobra.Command {
 	cronImporterCmd.AddCommand(NewCronJobDeleteCommand(p))
 	cronImporterCmd.AddCommand(NewCronJobDescribeCommand(p))
 	cronImporterCmd.AddCommand(NewCronJobUpdateCommand(p))
+	cronImporterCmd.AddCommand(NewCronJobListCommand(p))
 	return cronImporterCmd
 }
 
diff --git a/pkg/kn/commands/source/cronjob/flags.go b/pkg/kn/commands/source/cronjob/flags.go
index 5ea210a1..0970c1ee 100644
--- a/pkg/kn/commands/source/cronjob/flags.go
+++ b/pkg/kn/commands/source/cronjob/flags.go
@@ -14,7 +14,19 @@
 
 package cronjob
 
-import "github.com/spf13/cobra"
+import (
+	"fmt"
+	"sort"
+
+	"github.com/spf13/cobra"
+	metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1"
+	"k8s.io/apimachinery/pkg/runtime"
+
+	"knative.dev/client/pkg/kn/commands"
+	hprinters "knative.dev/client/pkg/printers"
+
+	"knative.dev/eventing/pkg/apis/sources/v1alpha1"
+)
 
 type cronJobUpdateFlags struct {
 	schedule string
@@ -25,3 +37,105 @@ func (c *cronJobUpdateFlags) addCronJobFlags(cmd *cobra.Command) {
 	cmd.Flags().StringVar(&c.schedule, "schedule", "", "Schedule specification in crontab format (e.g. '* * * * */2' for every two minutes")
 	cmd.Flags().StringVarP(&c.data, "data", "d", "", "String data to send")
 }
+
+// CronJobListHandlers handles printing human readable table for `kn source cronjob list` command's output
+func CronJobSourceListHandlers(h hprinters.PrintHandler) {
+	sourceColumnDefinitions := []metav1beta1.TableColumnDefinition{
+		{Name: "Namespace", Type: "string", Description: "Namespace of the CronJob source", Priority: 0},
+		{Name: "Name", Type: "string", Description: "Name of the CronJob source", Priority: 1},
+		{Name: "Schedule", Type: "string", Description: "Schedule of the CronJob source", Priority: 1},
+		{Name: "Sink", Type: "string", Description: "Sink of the CronJob source", Priority: 1},
+		{Name: "Conditions", Type: "string", Description: "Ready state conditions", Priority: 1},
+		{Name: "Ready", Type: "string", Description: "Ready state of the CronJob source", Priority: 1},
+		{Name: "Reason", Type: "string", Description: "Reason if state is not Ready", Priority: 1},
+	}
+	h.TableHandler(sourceColumnDefinitions, printSource)
+	h.TableHandler(sourceColumnDefinitions, printSourceList)
+}
+
+// printSource populates a single row of source cronjob list table
+func printSource(source *v1alpha1.CronJobSource, options hprinters.PrintOptions) ([]metav1beta1.TableRow, error) {
+	row := metav1beta1.TableRow{
+		Object: runtime.RawExtension{Object: source},
+	}
+
+	name := source.Name
+	schedule := source.Spec.Schedule
+	conditions := commands.ConditionsValue(source.Status.Conditions)
+	ready := commands.ReadyCondition(source.Status.Conditions)
+	reason := commands.NonReadyConditionReason(source.Status.Conditions)
+
+	var sink string
+	if source.Spec.Sink != nil {
+		if source.Spec.Sink.Ref != nil {
+			if source.Spec.Sink.Ref.Kind == "Service" {
+				sink = fmt.Sprintf("svc:%s", source.Spec.Sink.Ref.Name)
+			} else {
+				sink = fmt.Sprintf("%s:%s", source.Spec.Sink.Ref.Kind, source.Spec.Sink.Ref.Name)
+			}
+		}
+	}
+
+	if options.AllNamespaces {
+		row.Cells = append(row.Cells, source.Namespace)
+	}
+
+	row.Cells = append(row.Cells, name, schedule, sink, conditions, ready, reason)
+	return []metav1beta1.TableRow{row}, nil
+}
+
+// printSourceList populates the source cronjob list table rows
+func printSourceList(sourceList *v1alpha1.CronJobSourceList, options hprinters.PrintOptions) ([]metav1beta1.TableRow, error) {
+	if options.AllNamespaces {
+		return printSourceListWithNamespace(sourceList, options)
+	}
+
+	rows := make([]metav1beta1.TableRow, 0, len(sourceList.Items))
+
+	sort.SliceStable(sourceList.Items, func(i, j int) bool {
+		return sourceList.Items[i].GetName() < sourceList.Items[j].GetName()
+	})
+
+	for _, item := range sourceList.Items {
+		row, err := printSource(&item, options)
+		if err != nil {
+			return nil, err
+		}
+
+		rows = append(rows, row...)
+	}
+	return rows, nil
+}
+
+// printSourceListWithNamespace populates the knative service table rows with namespace column
+func printSourceListWithNamespace(sourceList *v1alpha1.CronJobSourceList, options hprinters.PrintOptions) ([]metav1beta1.TableRow, error) {
+	rows := make([]metav1beta1.TableRow, 0, len(sourceList.Items))
+
+	// temporary slice for sorting services in non-default namespace
+	others := []metav1beta1.TableRow{}
+
+	for _, source := range sourceList.Items {
+		// Fill in with services in `default` namespace at first
+		if source.Namespace == "default" {
+			r, err := printSource(&source, options)
+			if err != nil {
+				return nil, err
+			}
+			rows = append(rows, r...)
+			continue
+		}
+		// put other services in temporary slice
+		r, err := printSource(&source, options)
+		if err != nil {
+			return nil, err
+		}
+		others = append(others, r...)
+	}
+
+	// sort other services list alphabetically by namespace
+	sort.SliceStable(others, func(i, j int) bool {
+		return others[i].Cells[0].(string) < others[j].Cells[0].(string)
+	})
+
+	return append(rows, others...), nil
+}
diff --git a/pkg/kn/commands/source/cronjob/list.go b/pkg/kn/commands/source/cronjob/list.go
new file mode 100644
index 00000000..d6e0f063
--- /dev/null
+++ b/pkg/kn/commands/source/cronjob/list.go
@@ -0,0 +1,74 @@
+// Copyright © 2019 The Knative Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cronjob
+
+import (
+	"fmt"
+
+	"github.com/spf13/cobra"
+	"knative.dev/client/pkg/kn/commands"
+	"knative.dev/client/pkg/kn/commands/flags"
+)
+
+// NewCronJobListCommand is for listing CronJob source COs
+func NewCronJobListCommand(p *commands.KnParams) *cobra.Command {
+	listFlags := flags.NewListFlags(CronJobSourceListHandlers)
+
+	listCommand := &cobra.Command{
+		Use:   "list",
+		Short: "List CronJob sources.",
+		Example: `
+  # List all CronJob sources in YAML format
+  kn source cronjob list -o yaml`,
+
+		RunE: func(cmd *cobra.Command, args []string) (err error) {
+			// TODO: filter list by given source name
+
+			cronSourceClient, err := newCronJobSourceClient(p, cmd)
+			if err != nil {
+				return err
+			}
+
+			sourceList, err := cronSourceClient.ListCronJobSource()
+			if err != nil {
+				return err
+			}
+
+			if len(sourceList.Items) == 0 {
+				fmt.Fprintf(cmd.OutOrStdout(), "No CronJob source found.\n")
+				return nil
+			}
+
+			if cronSourceClient.Namespace() == "" {
+				listFlags.EnsureWithNamespace()
+			}
+
+			printer, err := listFlags.ToPrinter()
+			if err != nil {
+				return nil
+			}
+
+			err = printer.PrintObj(sourceList, cmd.OutOrStdout())
+			if err != nil {
+				return err
+			}
+
+			return nil
+		},
+	}
+	commands.AddNamespaceFlags(listCommand.Flags(), true)
+	listFlags.AddFlags(listCommand)
+	return listCommand
+}
diff --git a/pkg/kn/commands/trigger/create.go b/pkg/kn/commands/trigger/create.go
index e39c3625..bd8d5116 100644
--- a/pkg/kn/commands/trigger/create.go
+++ b/pkg/kn/commands/trigger/create.go
@@ -67,7 +67,19 @@ func NewTriggerCreateCommand(p *commands.KnParams) *cobra.Command {
 						"because %s", name, namespace, err)
 			}
 
-			trigger := constructTrigger(name, namespace, triggerUpdateFlags)
+			filters, err := triggerUpdateFlags.GetFilters()
+			if err != nil {
+				return fmt.Errorf(
+					"cannot create trigger '%s' "+
+						"because %s", name, err)
+			}
+			if filters == nil {
+				return fmt.Errorf(
+					"cannot create trigger '%s' "+
+						"because filters are required", name)
+			}
+
+			trigger := constructTrigger(name, namespace, triggerUpdateFlags.Broker, filters)
 			trigger.Spec.Subscriber = &duckv1.Destination{
 				Ref: objectRef.Ref,
 				URI: objectRef.URI,
@@ -87,28 +99,26 @@ func NewTriggerCreateCommand(p *commands.KnParams) *cobra.Command {
 	triggerUpdateFlags.Add(cmd)
 	sinkFlags.Add(cmd)
 	cmd.MarkFlagRequired("sink")
+	cmd.MarkFlagRequired("filter")
 
 	return cmd
 }
 
 // constructTrigger is to create an instance of v1alpha1.Trigger
-func constructTrigger(name string, namespace string, flags TriggerUpdateFlags) *v1alpha1.Trigger {
+func constructTrigger(name string, namespace string, broker string, filters map[string]string) *v1alpha1.Trigger {
 	trigger := v1alpha1.Trigger{
 		ObjectMeta: metav1.ObjectMeta{
 			Name:      name,
 			Namespace: namespace,
 		},
 		Spec: v1alpha1.TriggerSpec{
-			Broker: flags.Broker,
+			Broker: broker,
 		},
 	}
 
-	filters := flags.GetFilters()
-	if filters != nil {
-		triggerFilterAttributes := v1alpha1.TriggerFilterAttributes(filters)
-		trigger.Spec.Filter = &v1alpha1.TriggerFilter{
-			Attributes: &triggerFilterAttributes,
-		}
+	triggerFilterAttributes := v1alpha1.TriggerFilterAttributes(filters)
+	trigger.Spec.Filter = &v1alpha1.TriggerFilter{
+		Attributes: &triggerFilterAttributes,
 	}
 
 	return &trigger
diff --git a/pkg/kn/commands/trigger/trigger.go b/pkg/kn/commands/trigger/trigger.go
index e5158a2b..d6dfd9de 100644
--- a/pkg/kn/commands/trigger/trigger.go
+++ b/pkg/kn/commands/trigger/trigger.go
@@ -27,8 +27,9 @@ func NewTriggerCommand(p *commands.KnParams) *cobra.Command {
 		Short: "Trigger command group",
 	}
 	triggerCmd.AddCommand(NewTriggerCreateCommand(p))
-	triggerCmd.AddCommand(NewTriggerDeleteCommand(p))
+	triggerCmd.AddCommand(NewTriggerUpdateCommand(p))
 	triggerCmd.AddCommand(NewTriggerDescribeCommand(p))
 	triggerCmd.AddCommand(NewTriggerListCommand(p))
+	triggerCmd.AddCommand(NewTriggerDeleteCommand(p))
 	return triggerCmd
 }
diff --git a/pkg/kn/commands/trigger/update.go b/pkg/kn/commands/trigger/update.go
new file mode 100644
index 00000000..0b60a0d7
--- /dev/null
+++ b/pkg/kn/commands/trigger/update.go
@@ -0,0 +1,110 @@
+// Copyright © 2019 The Knative Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package trigger
+
+import (
+	"errors"
+	"fmt"
+
+	"github.com/spf13/cobra"
+
+	client_v1alpha1 "knative.dev/client/pkg/eventing/v1alpha1"
+	"knative.dev/client/pkg/kn/commands"
+	"knative.dev/client/pkg/kn/commands/flags"
+	duckv1 "knative.dev/pkg/apis/duck/v1"
+)
+
+// NewTriggerUpdateCommand prepares the command for a CronJobSource update
+func NewTriggerUpdateCommand(p *commands.KnParams) *cobra.Command {
+	var triggerUpdateFlags TriggerUpdateFlags
+	var sinkFlags flags.SinkFlags
+
+	cmd := &cobra.Command{
+		Use:   "update NAME --filter KEY=VALUE --sink SINK",
+		Short: "Update a trigger",
+		Example: `
+  # Update the filter which key is 'type' to value 'knative.dev.bar' in a trigger 'mytrigger'
+  kn trigger update mytrigger --filter type=knative.dev.bar
+
+  # Remove the filter which key is 'type' from a trigger 'mytrigger' 
+  kn trigger update mytrigger --filter type-
+
+  # Update the sink of a trigger 'mytrigger' to 'svc:new-service'
+  kn trigger update mytrigger --sink svc:new-service
+  `,
+
+		RunE: func(cmd *cobra.Command, args []string) (err error) {
+			if len(args) != 1 {
+				return errors.New("name of trigger required")
+			}
+			name := args[0]
+
+			namespace, err := p.GetNamespace(cmd)
+			if err != nil {
+				return err
+			}
+
+			eventingClient, err := p.NewEventingClient(namespace)
+			if err != nil {
+				return err
+			}
+
+			servingClient, err := p.NewServingClient(namespace)
+			if err != nil {
+				return err
+			}
+
+			trigger, err := eventingClient.GetTrigger(name)
+			if err != nil {
+				return err
+			}
+
+			b := client_v1alpha1.NewTriggerBuilderFromExisting(trigger)
+
+			if cmd.Flags().Changed("broker") {
+				return fmt.Errorf(
+					"cannot update trigger '%s' because broker is immutable", name)
+			}
+			if cmd.Flags().Changed("filter") {
+				updated, removed, err := triggerUpdateFlags.GetUpdateFilters()
+				if err != nil {
+					return fmt.Errorf(
+						"cannot update trigger '%s' because %s", name, err)
+				}
+				b.UpdateFilters(updated, removed)
+			}
+			if cmd.Flags().Changed("sink") {
+				destination, err := sinkFlags.ResolveSink(servingClient)
+				if err != nil {
+					return err
+				}
+				b.Sink(&duckv1.Destination{
+					Ref: destination.Ref,
+					URI: destination.URI,
+				})
+			}
+			err = eventingClient.UpdateTrigger(b.Build())
+			if err == nil {
+				fmt.Fprintf(cmd.OutOrStdout(), "Trigger '%s' updated in namespace '%s'.\n", name, namespace)
+			}
+			return err
+		},
+	}
+	commands.AddNamespaceFlags(cmd.Flags(), false)
+	triggerUpdateFlags.Add(cmd)
+	sinkFlags.Add(cmd)
+
+	return cmd
+}
diff --git a/pkg/kn/commands/trigger/update_flags.go b/pkg/kn/commands/trigger/update_flags.go
index be3b6012..a8847ed2 100644
--- a/pkg/kn/commands/trigger/update_flags.go
+++ b/pkg/kn/commands/trigger/update_flags.go
@@ -47,17 +47,35 @@ type TriggerUpdateFlags struct {
 }
 
 // GetFilter to return a map type of filters
-func (f *TriggerUpdateFlags) GetFilters() map[string]string {
+func (f *TriggerUpdateFlags) GetFilters() (map[string]string, error) {
 	filters := map[string]string{}
 	for _, item := range f.Filters {
 		parts := strings.Split(item, "=")
-		if len(parts) == 2 {
+		if len(parts) < 2 || parts[0] == "" || parts[1] == "" {
+			return nil, fmt.Errorf("invalid filter %s", f.Filters)
+		} else {
 			filters[parts[0]] = parts[1]
+		}
+	}
+	return filters, nil
+}
+
+// GetFilter to return a map type of filters
+func (f *TriggerUpdateFlags) GetUpdateFilters() (map[string]string, []string, error) {
+	filters := map[string]string{}
+	removes := []string{}
+	for _, item := range f.Filters {
+		if strings.HasSuffix(item, "-") {
+			removes = append(removes, item[:len(item)-1])
 		} else {
-			fmt.Printf("Ignore invalid filter %s", f)
+			parts := strings.Split(item, "=")
+			if len(parts) < 2 || parts[0] == "" || parts[1] == "" {
+				return nil, nil, fmt.Errorf("invalid filter %s", f.Filters)
+			}
+			filters[parts[0]] = parts[1]
 		}
 	}
-	return filters
+	return filters, removes, nil
 }
 
 //Add is to set parameters


Test patch:
diff --git a/pkg/eventing/sources/v1alpha1/apiserver_client_test.go b/pkg/eventing/sources/v1alpha1/apiserver_client_test.go
index fd149d6b..54bb1fa4 100644
--- a/pkg/eventing/sources/v1alpha1/apiserver_client_test.go
+++ b/pkg/eventing/sources/v1alpha1/apiserver_client_test.go
@@ -116,6 +116,20 @@ func TestUpdateApiServerSource(t *testing.T) {
 	assert.ErrorContains(t, err, "errorSource")
 }
 
+func TestListAPIServerSource(t *testing.T) {
+	sourcesServer, client := setupAPIServerSourcesClient(t)
+
+	sourcesServer.AddReactor("list", "apiserversources",
+		func(a client_testing.Action) (bool, runtime.Object, error) {
+			cJSource := newAPIServerSource("testsource", "Event")
+			return true, &v1alpha1.ApiServerSourceList{Items: []v1alpha1.ApiServerSource{*cJSource}}, nil
+		})
+
+	sourceList, err := client.ListAPIServerSource()
+	assert.NilError(t, err)
+	assert.Equal(t, len(sourceList.Items), 1)
+}
+
 func newAPIServerSource(name, resource string) *v1alpha1.ApiServerSource {
 	b := NewAPIServerSourceBuilder(name).ServiceAccount("testsa").Mode("Ref")
 	b.Sink(&v1beta1.Destination{
diff --git a/pkg/eventing/sources/v1alpha1/cronjob_client_test.go b/pkg/eventing/sources/v1alpha1/cronjob_client_test.go
index 6653f3ed..8cd732a3 100644
--- a/pkg/eventing/sources/v1alpha1/cronjob_client_test.go
+++ b/pkg/eventing/sources/v1alpha1/cronjob_client_test.go
@@ -119,6 +119,20 @@ func TestGetCronJobSource(t *testing.T) {
 	assert.ErrorContains(t, err, "errorSource")
 }
 
+func TestListCronJobSource(t *testing.T) {
+	sourcesServer, client := setupCronJobSourcesClient(t)
+
+	sourcesServer.AddReactor("list", "cronjobsources",
+		func(a client_testing.Action) (bool, runtime.Object, error) {
+			cJSource := newCronJobSource("testsource", "mysvc")
+			return true, &v1alpha1.CronJobSourceList{Items: []v1alpha1.CronJobSource{*cJSource}}, nil
+		})
+
+	sourceList, err := client.ListCronJobSource()
+	assert.NilError(t, err)
+	assert.Equal(t, len(sourceList.Items), 1)
+}
+
 func newCronJobSource(name string, sink string) *v1alpha1.CronJobSource {
 	b := NewCronJobSourceBuilder(name).
 		Schedule("* * * * *").
diff --git a/pkg/eventing/v1alpha1/client_mock_test.go b/pkg/eventing/v1alpha1/client_mock_test.go
index ffe746d6..129e4f7e 100644
--- a/pkg/eventing/v1alpha1/client_mock_test.go
+++ b/pkg/eventing/v1alpha1/client_mock_test.go
@@ -31,12 +31,14 @@ func TestMockKnClient(t *testing.T) {
 	recorder.CreateTrigger(&v1alpha1.Trigger{}, nil)
 	recorder.DeleteTrigger("hello", nil)
 	recorder.ListTriggers(nil, nil)
+	recorder.UpdateTrigger(&v1alpha1.Trigger{}, nil)
 
 	// Call all service
 	client.GetTrigger("hello")
 	client.CreateTrigger(&v1alpha1.Trigger{})
 	client.DeleteTrigger("hello")
 	client.ListTriggers()
+	client.UpdateTrigger(&v1alpha1.Trigger{})
 
 	// Validate
 	recorder.Validate()
diff --git a/pkg/eventing/v1alpha1/client_test.go b/pkg/eventing/v1alpha1/client_test.go
index 7f658037..efc38933 100644
--- a/pkg/eventing/v1alpha1/client_test.go
+++ b/pkg/eventing/v1alpha1/client_test.go
@@ -128,22 +128,54 @@ func TestListTrigger(t *testing.T) {
 	})
 }
 
-func newTrigger(name string) *v1alpha1.Trigger {
-	obj := &v1alpha1.Trigger{
-		ObjectMeta: metav1.ObjectMeta{
-			Name:      name,
-			Namespace: testNamespace,
-		},
-		Spec: v1alpha1.TriggerSpec{
-			Broker: "default",
-			Filter: &v1alpha1.TriggerFilter{
-				Attributes: &v1alpha1.TriggerFilterAttributes{
-					"type": "foo",
-				},
+func TestTriggerBuilder(t *testing.T) {
+	a := NewTriggerBuilder("testtrigger")
+	a.Filters(map[string]string{"type": "foo", "source": "bar"})
+
+	t.Run("update filter", func(t *testing.T) {
+		b := NewTriggerBuilderFromExisting(a.Build())
+		assert.DeepEqual(t, b.Build(), a.Build())
+		b.UpdateFilters(map[string]string{"type": "new"}, []string{"source"})
+		expected := &v1alpha1.TriggerFilter{
+			Attributes: &v1alpha1.TriggerFilterAttributes{
+				"type": "new",
+			},
+		}
+		assert.DeepEqual(t, expected, b.Build().Spec.Filter)
+	})
+
+	t.Run("update filter with only deletions", func(t *testing.T) {
+		b := NewTriggerBuilderFromExisting(a.Build())
+		assert.DeepEqual(t, b.Build(), a.Build())
+		b.UpdateFilters(nil, []string{"source"})
+		expected := &v1alpha1.TriggerFilter{
+			Attributes: &v1alpha1.TriggerFilterAttributes{
+				"type": "foo",
+			},
+		}
+		assert.DeepEqual(t, expected, b.Build().Spec.Filter)
+	})
+
+	t.Run("update filter with only updates", func(t *testing.T) {
+		b := NewTriggerBuilderFromExisting(a.Build())
+		assert.DeepEqual(t, b.Build(), a.Build())
+		b.UpdateFilters(map[string]string{"type": "new"}, nil)
+		expected := &v1alpha1.TriggerFilter{
+			Attributes: &v1alpha1.TriggerFilterAttributes{
+				"type":   "new",
+				"source": "bar",
 			},
-		},
-	}
-	obj.Name = name
-	obj.Namespace = testNamespace
-	return obj
+		}
+		assert.DeepEqual(t, expected, b.Build().Spec.Filter)
+	})
+
+}
+
+func newTrigger(name string) *v1alpha1.Trigger {
+	b := NewTriggerBuilder(name)
+	b.Filters(map[string]string{"type": "foo"})
+	b.Broker("default")
+	b.trigger.Name = name
+	b.trigger.Namespace = testNamespace
+	return b.Build()
 }
diff --git a/pkg/kn/commands/source/apiserver/list_test.go b/pkg/kn/commands/source/apiserver/list_test.go
new file mode 100644
index 00000000..93e68f7d
--- /dev/null
+++ b/pkg/kn/commands/source/apiserver/list_test.go
@@ -0,0 +1,59 @@
+// Copyright © 2019 The Knative Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package apiserver
+
+import (
+	"testing"
+
+	"gotest.tools/assert"
+
+	knsource_v1alpha1 "knative.dev/client/pkg/eventing/sources/v1alpha1"
+	"knative.dev/client/pkg/util"
+	"knative.dev/eventing/pkg/apis/sources/v1alpha1"
+)
+
+func TestListAPIServerSource(t *testing.T) {
+	apiServerClient := knsource_v1alpha1.NewMockKnAPIServerSourceClient(t)
+
+	apiServerRecorder := apiServerClient.Recorder()
+	sampleSource := createAPIServerSource("testsource", "Event", "v1", "testsa", "Ref", "testsvc", false)
+	sampleSourceList := v1alpha1.ApiServerSourceList{}
+	sampleSourceList.Items = []v1alpha1.ApiServerSource{*sampleSource}
+
+	apiServerRecorder.ListAPIServerSource(&sampleSourceList, nil)
+
+	out, err := executeAPIServerSourceCommand(apiServerClient, nil, "list")
+	assert.NilError(t, err, "sources should be listed")
+	util.ContainsAll(out, "NAME", "RESOURCES", "SINK", "CONDITIONS", "READY", "REASON")
+	util.ContainsAll(out, "testsource", "Eventing:v1:false", "mysvc")
+
+	apiServerRecorder.Validate()
+}
+
+func TestListAPIServerSourceEmpty(t *testing.T) {
+	apiServerClient := knsource_v1alpha1.NewMockKnAPIServerSourceClient(t)
+
+	apiServerRecorder := apiServerClient.Recorder()
+	sampleSourceList := v1alpha1.ApiServerSourceList{}
+
+	apiServerRecorder.ListAPIServerSource(&sampleSourceList, nil)
+
+	out, err := executeAPIServerSourceCommand(apiServerClient, nil, "list")
+	assert.NilError(t, err, "Sources should be listed")
+	util.ContainsNone(out, "NAME", "RESOURCES", "SINK", "CONDITIONS", "READY", "REASON")
+	util.ContainsAll(out, "No", "ApiServer", "source", "found")
+
+	apiServerRecorder.Validate()
+}
diff --git a/pkg/kn/commands/source/cronjob/list_test.go b/pkg/kn/commands/source/cronjob/list_test.go
new file mode 100644
index 00000000..86c65d8c
--- /dev/null
+++ b/pkg/kn/commands/source/cronjob/list_test.go
@@ -0,0 +1,59 @@
+// Copyright © 2019 The Knative Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cronjob
+
+import (
+	"testing"
+
+	"gotest.tools/assert"
+
+	knsource_v1alpha1 "knative.dev/client/pkg/eventing/sources/v1alpha1"
+	"knative.dev/client/pkg/util"
+	"knative.dev/eventing/pkg/apis/sources/v1alpha1"
+)
+
+func TestListCronJobSource(t *testing.T) {
+	cronjobClient := knsource_v1alpha1.NewMockKnCronJobSourceClient(t)
+
+	cronJobRecorder := cronjobClient.Recorder()
+	cJSource := createCronJobSource("testsource", "* * * * */2", "maxwell", "mysvc")
+	cJSourceList := v1alpha1.CronJobSourceList{}
+	cJSourceList.Items = []v1alpha1.CronJobSource{*cJSource}
+
+	cronJobRecorder.ListCronJobSource(&cJSourceList, nil)
+
+	out, err := executeCronJobSourceCommand(cronjobClient, nil, "list")
+	assert.NilError(t, err, "Sources should be listed")
+	util.ContainsAll(out, "NAME", "SCHEDULE", "SINK", "CONDITIONS", "READY", "REASON")
+	util.ContainsAll(out, "testsource", "* * * * */2", "mysvc")
+
+	cronJobRecorder.Validate()
+}
+
+func TestListCronJobSourceEmpty(t *testing.T) {
+	cronjobClient := knsource_v1alpha1.NewMockKnCronJobSourceClient(t)
+
+	cronJobRecorder := cronjobClient.Recorder()
+	cJSourceList := v1alpha1.CronJobSourceList{}
+
+	cronJobRecorder.ListCronJobSource(&cJSourceList, nil)
+
+	out, err := executeCronJobSourceCommand(cronjobClient, nil, "list")
+	assert.NilError(t, err, "Sources should be listed")
+	util.ContainsNone(out, "NAME", "SCHEDULE", "SINK", "CONDITIONS", "READY", "REASON")
+	util.ContainsAll(out, "No", "CronJob", "source", "found")
+
+	cronJobRecorder.Validate()
+}
diff --git a/pkg/kn/commands/trigger/create_test.go b/pkg/kn/commands/trigger/create_test.go
index 2c7ab2d6..d5b57203 100644
--- a/pkg/kn/commands/trigger/create_test.go
+++ b/pkg/kn/commands/trigger/create_test.go
@@ -75,6 +75,13 @@ func TestNoSinkError(t *testing.T) {
 	assert.ErrorContains(t, err, "required flag(s)", "sink", "not set")
 }
 
+func TestNoFilterError(t *testing.T) {
+	eventingClient := eventing_client.NewMockKnEventingClient(t)
+	_, err := executeTriggerCommand(eventingClient, nil, "create", triggerName, "--broker", "mybroker",
+		"--sink", "svc:mysvc")
+	assert.ErrorContains(t, err, "required flag(s)", "filter", "not set")
+}
+
 func TestTriggerCreateMultipleFilter(t *testing.T) {
 	eventingClient := eventing_client.NewMockKnEventingClient(t)
 	servingClient := knserving_client.NewMockKnServiceClient(t)
diff --git a/pkg/kn/commands/trigger/update_flags_test.go b/pkg/kn/commands/trigger/update_flags_test.go
index e82ff6fe..d383d815 100644
--- a/pkg/kn/commands/trigger/update_flags_test.go
+++ b/pkg/kn/commands/trigger/update_flags_test.go
@@ -20,16 +20,85 @@ import (
 	"gotest.tools/assert"
 )
 
-func TestGetFilter(t *testing.T) {
+func TestGetFilters(t *testing.T) {
 	t.Run("get multiple filters", func(t *testing.T) {
 		createFlag := TriggerUpdateFlags{
 			Filters: filterArray{"type=abc.edf.ghi", "attr=value"},
 		}
-		created := createFlag.GetFilters()
+		created, err := createFlag.GetFilters()
 		wanted := map[string]string{
 			"type": "abc.edf.ghi",
 			"attr": "value",
 		}
+		assert.NilError(t, err, "Filter should be created")
 		assert.DeepEqual(t, wanted, created)
 	})
+
+	t.Run("get filters with errors", func(t *testing.T) {
+		createFlag := TriggerUpdateFlags{
+			Filters: filterArray{"type"},
+		}
+		_, err := createFlag.GetFilters()
+		assert.ErrorContains(t, err, "invalid filter")
+
+		createFlag = TriggerUpdateFlags{
+			Filters: filterArray{"type="},
+		}
+		_, err = createFlag.GetFilters()
+		assert.ErrorContains(t, err, "invalid filter")
+
+		createFlag = TriggerUpdateFlags{
+			Filters: filterArray{"=value"},
+		}
+		_, err = createFlag.GetFilters()
+		assert.ErrorContains(t, err, "invalid filter")
+
+		createFlag = TriggerUpdateFlags{
+			Filters: filterArray{"="},
+		}
+		_, err = createFlag.GetFilters()
+		assert.ErrorContains(t, err, "invalid filter")
+	})
+}
+
+func TestGetUpdateFilters(t *testing.T) {
+	t.Run("get updated filters", func(t *testing.T) {
+		createFlag := TriggerUpdateFlags{
+			Filters: filterArray{"type=abc.edf.ghi", "attr=value"},
+		}
+		updated, removed, err := createFlag.GetUpdateFilters()
+		wanted := map[string]string{
+			"type": "abc.edf.ghi",
+			"attr": "value",
+		}
+		assert.NilError(t, err, "UpdateFilter should be created")
+		assert.DeepEqual(t, wanted, updated)
+		assert.Assert(t, len(removed) == 0)
+	})
+
+	t.Run("get deleted filters", func(t *testing.T) {
+		createFlag := TriggerUpdateFlags{
+			Filters: filterArray{"type-", "attr-"},
+		}
+		updated, removed, err := createFlag.GetUpdateFilters()
+		wanted := []string{"type", "attr"}
+		assert.NilError(t, err, "UpdateFilter should be created")
+		assert.DeepEqual(t, wanted, removed)
+		assert.Assert(t, len(updated) == 0)
+	})
+
+	t.Run("get updated & deleted filters", func(t *testing.T) {
+		createFlag := TriggerUpdateFlags{
+			Filters: filterArray{"type=foo", "attr-", "source=bar", "env-"},
+		}
+		updated, removed, err := createFlag.GetUpdateFilters()
+		wantedRemoved := []string{"attr", "env"}
+		wantedUpdated := map[string]string{
+			"type":   "foo",
+			"source": "bar",
+		}
+		assert.NilError(t, err, "UpdateFilter should be created")
+		assert.DeepEqual(t, wantedRemoved, removed)
+		assert.DeepEqual(t, wantedUpdated, updated)
+	})
 }
diff --git a/pkg/kn/commands/trigger/update_test.go b/pkg/kn/commands/trigger/update_test.go
new file mode 100644
index 00000000..0fba1db8
--- /dev/null
+++ b/pkg/kn/commands/trigger/update_test.go
@@ -0,0 +1,79 @@
+// Copyright © 2019 The Knative Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package trigger
+
+import (
+	"fmt"
+	"testing"
+
+	"gotest.tools/assert"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	eventing_client "knative.dev/client/pkg/eventing/v1alpha1"
+	knserving_client "knative.dev/client/pkg/serving/v1alpha1"
+	"knative.dev/client/pkg/util"
+	serving_v1alpha1 "knative.dev/serving/pkg/apis/serving/v1alpha1"
+)
+
+func TestTriggerUpdate(t *testing.T) {
+	eventingClient := eventing_client.NewMockKnEventingClient(t)
+	servingClient := knserving_client.NewMockKnServiceClient(t)
+
+	servingRecorder := servingClient.Recorder()
+	servingRecorder.GetService("mysvc", &serving_v1alpha1.Service{
+		TypeMeta:   metav1.TypeMeta{Kind: "Service"},
+		ObjectMeta: metav1.ObjectMeta{Name: "mysvc"},
+	}, nil)
+
+	eventingRecorder := eventingClient.Recorder()
+	present := createTrigger("default", triggerName, map[string]string{"type": "dev.knative.foo"}, "mybroker", "mysvc")
+	updated := createTrigger("default", triggerName, map[string]string{"type": "dev.knative.new"}, "mybroker", "mysvc")
+	eventingRecorder.GetTrigger(triggerName, present, nil)
+	eventingRecorder.UpdateTrigger(updated, nil)
+
+	out, err := executeTriggerCommand(eventingClient, servingClient, "update", triggerName,
+		"--filter", "type=dev.knative.new", "--sink", "svc:mysvc")
+	assert.NilError(t, err, "Trigger should be updated")
+	util.ContainsAll(out, "Trigger", triggerName, "updated", "namespace", "default")
+
+	eventingRecorder.Validate()
+	servingRecorder.Validate()
+}
+
+func TestTriggerUpdateWithError(t *testing.T) {
+	eventingClient := eventing_client.NewMockKnEventingClient(t)
+	eventingRecorder := eventingClient.Recorder()
+	eventingRecorder.GetTrigger(triggerName, nil, fmt.Errorf("trigger not found"))
+
+	out, err := executeTriggerCommand(eventingClient, nil, "update", triggerName,
+		"--filter", "type=dev.knative.new", "--sink", "svc:newsvc")
+	assert.ErrorContains(t, err, "trigger not found")
+	util.ContainsAll(out, "Usage", triggerName)
+
+	eventingRecorder.Validate()
+}
+
+func TestTriggerUpdateInvalidBroker(t *testing.T) {
+	eventingClient := eventing_client.NewMockKnEventingClient(t)
+	eventingRecorder := eventingClient.Recorder()
+	present := createTrigger("default", triggerName, map[string]string{"type": "dev.knative.new"}, "mybroker", "newsvc")
+	eventingRecorder.GetTrigger(triggerName, present, nil)
+
+	out, err := executeTriggerCommand(eventingClient, nil, "update", triggerName,
+		"--broker", "newbroker")
+	assert.ErrorContains(t, err, "broker is immutable")
+	util.ContainsAll(out, "Usage", triggerName)
+
+	eventingRecorder.Validate()
+}