Repository: knative/client (go)

Issue:
Add WithLabel list filter to serving client lib
<!-- If you need to report a security issue with Knative, send an email to knative-security@googlegroups.com. -->

### Feature request

The list filters in serving client lib are missing an option to filter by specified label, eg. something similar that could be achieved by this call:
```go
servingClient.Services(l.namespace).List(metav1.ListOptions{LabelSelector: labelSelector})
```

Serving Client lib:
https://github.com/knative/client/blob/b13cd70490587f22ec88831d657c0daf38ed4308/pkg/serving/v1/client.go#L110-L142

Would be nice to add `func WithLabel(labelKey, labelValue string) ListConfig`

<!--
Optional Classifications, remove the '> ' to select:
> /kind good-first-issue
 /kind proposal
> /kind doc
> /kind cleanup
-->


Pull request description:
Add WithLabel list filter to serving client lib
Signed-off-by: Zbynek Roubalik <zroubali@redhat.com>


## Description

Adding `WithLabel` list filter to serving client lib, which is missing currently. This allows to filter lists by labels.


## Reference

<!-- Please add the corresponding issue number which this pull request is about to fix -->
Fixes #1053 

<!--
Please add an entrty to CHANGELOG.adoc file, too, as part of your Pull Request.

In the following cases, add a short description of PR to the unreleased section in CHANGELOG.adoc:

- 🎁 New feature
- 🐛 Bug fix
- ✨ Feature Update
- 🐣 Refactoring
- 🗑️ Remove feature or internal logic

See other entries in CHANGELOG.adoc as an example for how to add the entry, including a reference to the corresponding issue/PR

PLEASE DON'T ADD THAT LINE HERE IN THE PULL-REQUEST DESCRIPTION BUT DIRECTLY IN CHANGELOG.ADOC AND ADD CHANGELOG.ADOC AS PART OF YOUR PULL-REQUEST.
-->

<!--
To automatically lint go code in this pull request uncomment the line below. You get feedback as comments on your pull request then -->


/lint



Patch:
diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc
index 9ab182ed..3fb0c91b 100644
--- a/CHANGELOG.adoc
+++ b/CHANGELOG.adoc
@@ -19,6 +19,10 @@
 | 🎁
 | Add Aliases to Help Command and Remove Aliases in Short
 | https://github.com/knative/client/pull/1055[#1055]
+
+| 🎁
+| Add WithLabel list filter to serving client lib
+| https://github.com/knative/client/pull/1054[#1054]
 |===
 
 ## v0.18.0 (2020-10-07)
diff --git a/docs/cmd/kn.md b/docs/cmd/kn.md
index 978bb876..1bae3510 100644
--- a/docs/cmd/kn.md
+++ b/docs/cmd/kn.md
@@ -19,7 +19,7 @@ kn is the command line interface for managing Knative Serving and Eventing resou
 
 ### SEE ALSO
 
-* [kn broker](kn_broker.md)	 - Manage message
+* [kn broker](kn_broker.md)	 - Manage message brokers
 * [kn channel](kn_channel.md)	 - Manage event channels
 * [kn completion](kn_completion.md)	 - Output shell completion code
 * [kn options](kn_options.md)	 - Print the list of flags inherited by all commands
diff --git a/docs/cmd/kn_broker.md b/docs/cmd/kn_broker.md
index 24f574f8..27c8d943 100644
--- a/docs/cmd/kn_broker.md
+++ b/docs/cmd/kn_broker.md
@@ -1,10 +1,10 @@
 ## kn broker
 
-Manage message
+Manage message brokers
 
 ### Synopsis
 
-Manage message
+Manage message brokers
 
 ```
 kn broker
diff --git a/docs/cmd/kn_broker_create.md b/docs/cmd/kn_broker_create.md
index 4086ca39..e11f5b97 100644
--- a/docs/cmd/kn_broker_create.md
+++ b/docs/cmd/kn_broker_create.md
@@ -38,5 +38,5 @@ kn broker create NAME
 
 ### SEE ALSO
 
-* [kn broker](kn_broker.md)	 - Manage message
+* [kn broker](kn_broker.md)	 - Manage message brokers
 
diff --git a/docs/cmd/kn_broker_delete.md b/docs/cmd/kn_broker_delete.md
index 6723e071..551fff50 100644
--- a/docs/cmd/kn_broker_delete.md
+++ b/docs/cmd/kn_broker_delete.md
@@ -42,5 +42,5 @@ kn broker delete NAME
 
 ### SEE ALSO
 
-* [kn broker](kn_broker.md)	 - Manage message
+* [kn broker](kn_broker.md)	 - Manage message brokers
 
diff --git a/docs/cmd/kn_broker_describe.md b/docs/cmd/kn_broker_describe.md
index 53cab698..454fc0e7 100644
--- a/docs/cmd/kn_broker_describe.md
+++ b/docs/cmd/kn_broker_describe.md
@@ -38,5 +38,5 @@ kn broker describe NAME
 
 ### SEE ALSO
 
-* [kn broker](kn_broker.md)	 - Manage message
+* [kn broker](kn_broker.md)	 - Manage message brokers
 
diff --git a/docs/cmd/kn_broker_list.md b/docs/cmd/kn_broker_list.md
index b7fe02a3..4b4613ae 100644
--- a/docs/cmd/kn_broker_list.md
+++ b/docs/cmd/kn_broker_list.md
@@ -43,5 +43,5 @@ kn broker list
 
 ### SEE ALSO
 
-* [kn broker](kn_broker.md)	 - Manage message
+* [kn broker](kn_broker.md)	 - Manage message brokers
 
diff --git a/pkg/kn/commands/broker/broker.go b/pkg/kn/commands/broker/broker.go
index 8502c05b..b5202f25 100644
--- a/pkg/kn/commands/broker/broker.go
+++ b/pkg/kn/commands/broker/broker.go
@@ -26,7 +26,7 @@ import (
 func NewBrokerCommand(p *commands.KnParams) *cobra.Command {
 	brokerCmd := &cobra.Command{
 		Use:     "broker",
-		Short:   "Manage message",
+		Short:   "Manage message brokers",
 		Aliases: []string{"brokers"},
 	}
 	brokerCmd.AddCommand(NewBrokerCreateCommand(p))
diff --git a/pkg/serving/v1/client.go b/pkg/serving/v1/client.go
index 0276fa0c..b464eebf 100644
--- a/pkg/serving/v1/client.go
+++ b/pkg/serving/v1/client.go
@@ -141,6 +141,13 @@ func WithService(service string) ListConfig {
 	}
 }
 
+// WithLabel filters on the provided label
+func WithLabel(labelKey, labelValue string) ListConfig {
+	return func(lo *listConfigCollector) {
+		lo.Labels[labelKey] = labelValue
+	}
+}
+
 type knServingClient struct {
 	client    clientv1.ServingV1Interface
 	namespace string


Test patch:
diff --git a/pkg/serving/v1/client_mock_test.go b/pkg/serving/v1/client_mock_test.go
index ec85dd76..10f20b70 100644
--- a/pkg/serving/v1/client_mock_test.go
+++ b/pkg/serving/v1/client_mock_test.go
@@ -34,6 +34,7 @@ func TestMockKnClient(t *testing.T) {
 	// Record all services
 	recorder.GetService("hello", nil, nil)
 	recorder.ListServices(mock.Any(), nil, nil)
+	recorder.ListServices(mock.Any(), nil, nil)
 	recorder.CreateService(&servingv1.Service{}, nil)
 	recorder.UpdateService(&servingv1.Service{}, nil)
 	recorder.DeleteService("hello", time.Duration(10)*time.Second, nil)
@@ -48,6 +49,7 @@ func TestMockKnClient(t *testing.T) {
 	// Call all services
 	client.GetService("hello")
 	client.ListServices(WithName("blub"))
+	client.ListServices(WithLabel("foo", "bar"))
 	client.CreateService(&servingv1.Service{})
 	client.UpdateService(&servingv1.Service{})
 	client.DeleteService("hello", time.Duration(10)*time.Second)
diff --git a/pkg/serving/v1/client_test.go b/pkg/serving/v1/client_test.go
index 766ec13c..37edf62d 100644
--- a/pkg/serving/v1/client_test.go
+++ b/pkg/serving/v1/client_test.go
@@ -85,24 +85,45 @@ func TestListService(t *testing.T) {
 	serving, client := setup()
 
 	t.Run("list service returns a list of services", func(t *testing.T) {
+		labelKey := "labelKey"
+		labelValue := "labelValue"
+		labels := map[string]string{labelKey: labelValue}
+		incorrectLabels := map[string]string{"foo": "bar"}
+
 		service1 := newService("service-1")
 		service2 := newService("service-2")
+		service3 := newService("service-3-with-label")
+		service3.Labels = labels
+		service4 := newService("service-4-with-label")
+		service4.Labels = labels
+		service5 := newService("service-5-with-incorrect-label")
+		service5.Labels = incorrectLabels
 
 		serving.AddReactor("list", "services",
 			func(a clienttesting.Action) (bool, runtime.Object, error) {
 				assert.Equal(t, testNamespace, a.GetNamespace())
-				return true, &servingv1.ServiceList{Items: []servingv1.Service{*service1, *service2}}, nil
+				return true, &servingv1.ServiceList{Items: []servingv1.Service{*service1, *service2, *service3, *service4, *service5}}, nil
 			})
 
 		listServices, err := client.ListServices()
 		assert.NilError(t, err)
-		assert.Assert(t, len(listServices.Items) == 2)
+		assert.Assert(t, len(listServices.Items) == 5)
 		assert.Equal(t, listServices.Items[0].Name, "service-1")
 		assert.Equal(t, listServices.Items[1].Name, "service-2")
 		validateGroupVersionKind(t, listServices)
 		validateGroupVersionKind(t, &listServices.Items[0])
 		validateGroupVersionKind(t, &listServices.Items[1])
+
+		listFilteredServices, err := client.ListServices(WithLabel(labelKey, labelValue))
+		assert.NilError(t, err)
+		assert.Assert(t, len(listFilteredServices.Items) == 2)
+		assert.Equal(t, listFilteredServices.Items[0].Name, "service-3-with-label")
+		assert.Equal(t, listFilteredServices.Items[1].Name, "service-4-with-label")
+		validateGroupVersionKind(t, listFilteredServices)
+		validateGroupVersionKind(t, &listFilteredServices.Items[0])
+		validateGroupVersionKind(t, &listFilteredServices.Items[1])
 	})
+
 }
 
 func TestCreateService(t *testing.T) {