Repository: knative/client
Pull request #1040 (2020-10-02 10:34:11)

[v0.17.1]: Backport PR for v0.17.1
- Cherry-pick:
  - #1005 
  - #1013 
- Update CHANGELOG
- Conform with k8s.io/api v0.17.6


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

This pull-request has been approved by: *<a href="https://github.com/knative/client/pull/1040#" title="Author self-approved">navidshaikh</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/release-0.17/OWNERS)~~ [navidshaikh]

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":[]} -->
knative-prow-robot: @navidshaikh: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-knative-client-unit-tests | b3c6cb8d9bb90eb739a9fed466f5c0d876125b8d | [link](https://prow.knative.dev/view/gs/knative-prow/pr-logs/pull/knative_client/1040/pull-knative-client-unit-tests/1311978068058836993) | `/test pull-knative-client-unit-tests`

[Full PR test history](https://gubernator.knative.dev/pr/knative_client/1040). [Your PR dashboard](https://gubernator.knative.dev/pr/navidshaikh).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
knative-prow-robot: @navidshaikh: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-knative-client-unit-tests | b3c6cb8d9bb90eb739a9fed466f5c0d876125b8d | [link](https://prow.knative.dev/view/gs/knative-prow/pr-logs/pull/knative_client/1040/pull-knative-client-unit-tests/1311978068058836993) | `/test pull-knative-client-unit-tests`
pull-knative-client-build-tests | b3c6cb8d9bb90eb739a9fed466f5c0d876125b8d | [link](https://prow.knative.dev/view/gs/knative-prow/pr-logs/pull/knative_client/1040/pull-knative-client-build-tests/1311978068058836992) | `/test pull-knative-client-build-tests`

[Full PR test history](https://gubernator.knative.dev/pr/knative_client/1040). [Your PR dashboard](https://gubernator.knative.dev/pr/navidshaikh).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
knative-prow-robot: @navidshaikh: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-knative-client-unit-tests | b3c6cb8d9bb90eb739a9fed466f5c0d876125b8d | [link](https://prow.knative.dev/view/gs/knative-prow/pr-logs/pull/knative_client/1040/pull-knative-client-unit-tests/1311978068058836993) | `/test pull-knative-client-unit-tests`
pull-knative-client-build-tests | b3c6cb8d9bb90eb739a9fed466f5c0d876125b8d | [link](https://prow.knative.dev/view/gs/knative-prow/pr-logs/pull/knative_client/1040/pull-knative-client-build-tests/1311978068058836992) | `/test pull-knative-client-build-tests`
pull-knative-client-integration-tests | b3c6cb8d9bb90eb739a9fed466f5c0d876125b8d | [link](https://prow.knative.dev/view/gs/knative-prow/pr-logs/pull/knative_client/1040/pull-knative-client-integration-tests/1311978068054642689) | `/test pull-knative-client-integration-tests`

[Full PR test history](https://gubernator.knative.dev/pr/knative_client/1040). [Your PR dashboard](https://gubernator.knative.dev/pr/navidshaikh).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
knative-prow-robot: @navidshaikh: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-knative-client-unit-tests | b3c6cb8d9bb90eb739a9fed466f5c0d876125b8d | [link](https://prow.knative.dev/view/gs/knative-prow/pr-logs/pull/knative_client/1040/pull-knative-client-unit-tests/1311978068058836993) | `/test pull-knative-client-unit-tests`
pull-knative-client-build-tests | b3c6cb8d9bb90eb739a9fed466f5c0d876125b8d | [link](https://prow.knative.dev/view/gs/knative-prow/pr-logs/pull/knative_client/1040/pull-knative-client-build-tests/1311978068058836992) | `/test pull-knative-client-build-tests`
pull-knative-client-integration-tests | b3c6cb8d9bb90eb739a9fed466f5c0d876125b8d | [link](https://prow.knative.dev/view/gs/knative-prow/pr-logs/pull/knative_client/1040/pull-knative-client-integration-tests/1311978068054642689) | `/test pull-knative-client-integration-tests`
pull-knative-client-integration-tests-latest-release | b3c6cb8d9bb90eb739a9fed466f5c0d876125b8d | [link](https://prow.knative.dev/view/gs/knative-prow/pr-logs/pull/knative_client/1040/pull-knative-client-integration-tests-latest-release/1311978068058836994) | `/test pull-knative-client-integration-tests-latest-release`

[Full PR test history](https://gubernator.knative.dev/pr/knative_client/1040). [Your PR dashboard](https://gubernator.knative.dev/pr/navidshaikh).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
knative-prow-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/knative/client/pull/1040#" title="Author self-approved">navidshaikh</a>*, *<a href="https://github.com/knative/client/pull/1040#pullrequestreview-501033305" title="LGTM">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/release-0.17/OWNERS)~~ [navidshaikh,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":[]} -->
knative-prow-robot: @navidshaikh: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-knative-client-integration-tests-latest-release | 249bb7de4fef6cafb2f833904dcec409f10552d6 | [link](https://prow.knative.dev/view/gs/knative-prow/pr-logs/pull/knative_client/1040/pull-knative-client-integration-tests-latest-release/1311983856026390530) | `/test pull-knative-client-integration-tests-latest-release`

[Full PR test history](https://gubernator.knative.dev/pr/knative_client/1040). [Your PR dashboard](https://gubernator.knative.dev/pr/navidshaikh).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
navidshaikh: /retest


     SubscriptionNotMarkedReadyByChannel : Failed to get subscription status: subscription "sub0" not present in channel "c0" subscriber's list
rhuss: /lgtm

Patch:
diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc
index 0a0f5370..f3c8898f 100644
--- a/CHANGELOG.adoc
+++ b/CHANGELOG.adoc
@@ -12,6 +12,22 @@
 | https://github.com/knative/client/pull/[#]
 ////
 
+## v0.17.1 (2020-10-02)
+
+[cols="1,10,3", options="header", width="100%"]
+|===
+| | Description | PR
+
+| 🎁
+| Add subscription CRUD
+| https://github.com/knative/client/pull/1013[#1013]
+
+| 🐛
+| Fix channel create example with inbuilt alias for imcv1beta1
+| https://github.com/knative/client/pull/1005[#1005]
+
+|===
+
 ## v0.17.0 (2020-08-26)
 
 [cols="1,10,3", options="header", width="100%"]
diff --git a/docs/cmd/kn.md b/docs/cmd/kn.md
index affc0162..f00dd7e3 100644
--- a/docs/cmd/kn.md
+++ b/docs/cmd/kn.md
@@ -28,6 +28,7 @@ kn is the command line interface for managing Knative Serving and Eventing resou
 * [kn route](kn_route.md)	 - List and describe service routes
 * [kn service](kn_service.md)	 - Manage Knative services
 * [kn source](kn_source.md)	 - Manage event sources
+* [kn subscription](kn_subscription.md)	 - Manage event subscriptions
 * [kn trigger](kn_trigger.md)	 - Manage event triggers
 * [kn version](kn_version.md)	 - Show the version of this client
 
diff --git a/docs/cmd/kn_channel_create.md b/docs/cmd/kn_channel_create.md
index c709efe7..f22febe4 100644
--- a/docs/cmd/kn_channel_create.md
+++ b/docs/cmd/kn_channel_create.md
@@ -17,8 +17,8 @@ kn channel create NAME
   # Create a channel 'pipe' with default setting for channel configuration
   kn channel create pipe
 
-  # Create a channel 'imc1' of type InMemoryChannel using inbuilt alias 'imc'
-  kn channel create imc1 --type imc
+  # Create a channel 'imc1' of type InMemoryChannel using inbuilt alias 'imcv1beta1'
+  kn channel create imc1 --type imcv1beta1
   # same as above without using inbuilt alias but providing explicit GVK
   kn channel create imc1 --type messaging.knative.dev:v1beta1:InMemoryChannel
 
diff --git a/docs/cmd/kn_source_apiserver_create.md b/docs/cmd/kn_source_apiserver_create.md
index d9b84bcc..a26f9627 100644
--- a/docs/cmd/kn_source_apiserver_create.md
+++ b/docs/cmd/kn_source_apiserver_create.md
@@ -30,7 +30,7 @@ kn source apiserver create NAME --resource RESOURCE --sink SINK
       --resource stringArray      Specification for which events to listen, in the format Kind:APIVersion:LabelSelector, e.g. "Event:v1:key=value".
                                   "LabelSelector" is a list of comma separated key value pairs. "LabelSelector" can be omitted, e.g. "Event:v1".
       --service-account string    Name of the service account to use to run this source
-  -s, --sink string               Addressable sink for events. You can specify a broker, Knative service or URI. Examples: '--sink broker:nest' for a broker 'nest', '--sink https://event.receiver.uri' for an URI with an 'http://' or 'https://' schema, '--sink 'ksvc:receiver' or simply '--sink receiver' for a Knative service 'receiver'. If prefix is not provided, it is considered as a Knative service.
+  -s, --sink string               Addressable sink for events. You can specify a broker, Knative service or URI. Examples: '--sink broker:nest' for a broker 'nest', '--sink https://event.receiver.uri' for an URI with an 'http://' or 'https://' schema, '--sink ksvc:receiver' or simply '--sink receiver' for a Knative service 'receiver'. If a prefix is not provided, it is considered as a Knative service.
 ```
 
 ### Options inherited from parent commands
diff --git a/docs/cmd/kn_source_apiserver_update.md b/docs/cmd/kn_source_apiserver_update.md
index e9672544..2982dd40 100644
--- a/docs/cmd/kn_source_apiserver_update.md
+++ b/docs/cmd/kn_source_apiserver_update.md
@@ -30,7 +30,7 @@ kn source apiserver update NAME
       --resource stringArray      Specification for which events to listen, in the format Kind:APIVersion:LabelSelector, e.g. "Event:v1:key=value".
                                   "LabelSelector" is a list of comma separated key value pairs. "LabelSelector" can be omitted, e.g. "Event:v1".
       --service-account string    Name of the service account to use to run this source
-  -s, --sink string               Addressable sink for events. You can specify a broker, Knative service or URI. Examples: '--sink broker:nest' for a broker 'nest', '--sink https://event.receiver.uri' for an URI with an 'http://' or 'https://' schema, '--sink 'ksvc:receiver' or simply '--sink receiver' for a Knative service 'receiver'. If prefix is not provided, it is considered as a Knative service.
+  -s, --sink string               Addressable sink for events. You can specify a broker, Knative service or URI. Examples: '--sink broker:nest' for a broker 'nest', '--sink https://event.receiver.uri' for an URI with an 'http://' or 'https://' schema, '--sink ksvc:receiver' or simply '--sink receiver' for a Knative service 'receiver'. If a prefix is not provided, it is considered as a Knative service.
 ```
 
 ### Options inherited from parent commands
diff --git a/docs/cmd/kn_source_binding_create.md b/docs/cmd/kn_source_binding_create.md
index abb619f0..0a36b9ba 100644
--- a/docs/cmd/kn_source_binding_create.md
+++ b/docs/cmd/kn_source_binding_create.md
@@ -24,7 +24,7 @@ kn source binding create NAME --subject SUBJECT --sink SINK
       --ce-override stringArray   Cloud Event overrides to apply before sending event to sink. Example: '--ce-override key=value' You may be provide this flag multiple times. To unset, append "-" to the key (e.g. --ce-override key-).
   -h, --help                      help for create
   -n, --namespace string          Specify the namespace to operate in.
-  -s, --sink string               Addressable sink for events. You can specify a broker, Knative service or URI. Examples: '--sink broker:nest' for a broker 'nest', '--sink https://event.receiver.uri' for an URI with an 'http://' or 'https://' schema, '--sink 'ksvc:receiver' or simply '--sink receiver' for a Knative service 'receiver'. If prefix is not provided, it is considered as a Knative service.
+  -s, --sink string               Addressable sink for events. You can specify a broker, Knative service or URI. Examples: '--sink broker:nest' for a broker 'nest', '--sink https://event.receiver.uri' for an URI with an 'http://' or 'https://' schema, '--sink ksvc:receiver' or simply '--sink receiver' for a Knative service 'receiver'. If a prefix is not provided, it is considered as a Knative service.
       --subject string            Subject which emits cloud events. This argument takes format kind:apiVersion:name for named resources or kind:apiVersion:labelKey1=value1,labelKey2=value2 for matching via a label selector
 ```
 
diff --git a/docs/cmd/kn_source_binding_update.md b/docs/cmd/kn_source_binding_update.md
index 82131378..b3a76743 100644
--- a/docs/cmd/kn_source_binding_update.md
+++ b/docs/cmd/kn_source_binding_update.md
@@ -24,7 +24,7 @@ kn source binding update NAME
       --ce-override stringArray   Cloud Event overrides to apply before sending event to sink. Example: '--ce-override key=value' You may be provide this flag multiple times. To unset, append "-" to the key (e.g. --ce-override key-).
   -h, --help                      help for update
   -n, --namespace string          Specify the namespace to operate in.
-  -s, --sink string               Addressable sink for events. You can specify a broker, Knative service or URI. Examples: '--sink broker:nest' for a broker 'nest', '--sink https://event.receiver.uri' for an URI with an 'http://' or 'https://' schema, '--sink 'ksvc:receiver' or simply '--sink receiver' for a Knative service 'receiver'. If prefix is not provided, it is considered as a Knative service.
+  -s, --sink string               Addressable sink for events. You can specify a broker, Knative service or URI. Examples: '--sink broker:nest' for a broker 'nest', '--sink https://event.receiver.uri' for an URI with an 'http://' or 'https://' schema, '--sink ksvc:receiver' or simply '--sink receiver' for a Knative service 'receiver'. If a prefix is not provided, it is considered as a Knative service.
       --subject string            Subject which emits cloud events. This argument takes format kind:apiVersion:name for named resources or kind:apiVersion:labelKey1=value1,labelKey2=value2 for matching via a label selector
 ```
 
diff --git a/docs/cmd/kn_source_ping_create.md b/docs/cmd/kn_source_ping_create.md
index 14f10355..d291b521 100644
--- a/docs/cmd/kn_source_ping_create.md
+++ b/docs/cmd/kn_source_ping_create.md
@@ -26,7 +26,7 @@ kn source ping create NAME --sink SINK
   -h, --help                      help for create
   -n, --namespace string          Specify the namespace to operate in.
       --schedule string           Optional schedule specification in crontab format (e.g. '*/2 * * * *' for every two minutes. By default fire every minute.
-  -s, --sink string               Addressable sink for events. You can specify a broker, Knative service or URI. Examples: '--sink broker:nest' for a broker 'nest', '--sink https://event.receiver.uri' for an URI with an 'http://' or 'https://' schema, '--sink 'ksvc:receiver' or simply '--sink receiver' for a Knative service 'receiver'. If prefix is not provided, it is considered as a Knative service.
+  -s, --sink string               Addressable sink for events. You can specify a broker, Knative service or URI. Examples: '--sink broker:nest' for a broker 'nest', '--sink https://event.receiver.uri' for an URI with an 'http://' or 'https://' schema, '--sink ksvc:receiver' or simply '--sink receiver' for a Knative service 'receiver'. If a prefix is not provided, it is considered as a Knative service.
 ```
 
 ### Options inherited from parent commands
diff --git a/docs/cmd/kn_source_ping_update.md b/docs/cmd/kn_source_ping_update.md
index fe09b806..99c1c693 100644
--- a/docs/cmd/kn_source_ping_update.md
+++ b/docs/cmd/kn_source_ping_update.md
@@ -26,7 +26,7 @@ kn source ping update NAME
   -h, --help                      help for update
   -n, --namespace string          Specify the namespace to operate in.
       --schedule string           Optional schedule specification in crontab format (e.g. '*/2 * * * *' for every two minutes. By default fire every minute.
-  -s, --sink string               Addressable sink for events. You can specify a broker, Knative service or URI. Examples: '--sink broker:nest' for a broker 'nest', '--sink https://event.receiver.uri' for an URI with an 'http://' or 'https://' schema, '--sink 'ksvc:receiver' or simply '--sink receiver' for a Knative service 'receiver'. If prefix is not provided, it is considered as a Knative service.
+  -s, --sink string               Addressable sink for events. You can specify a broker, Knative service or URI. Examples: '--sink broker:nest' for a broker 'nest', '--sink https://event.receiver.uri' for an URI with an 'http://' or 'https://' schema, '--sink ksvc:receiver' or simply '--sink receiver' for a Knative service 'receiver'. If a prefix is not provided, it is considered as a Knative service.
 ```
 
 ### Options inherited from parent commands
diff --git a/docs/cmd/kn_subscription.md b/docs/cmd/kn_subscription.md
new file mode 100644
index 00000000..640bb9a3
--- /dev/null
+++ b/docs/cmd/kn_subscription.md
@@ -0,0 +1,35 @@
+## kn subscription
+
+Manage event subscriptions
+
+### Synopsis
+
+Manage event subscriptions
+
+```
+kn subscription COMMAND
+```
+
+### Options
+
+```
+  -h, --help   help for subscription
+```
+
+### Options inherited from parent commands
+
+```
+      --config string       kn configuration file (default: ~/.config/kn/config.yaml)
+      --kubeconfig string   kubectl configuration file (default: ~/.kube/config)
+      --log-http            log http traffic
+```
+
+### SEE ALSO
+
+* [kn](kn.md)	 - kn manages Knative Serving and Eventing resources
+* [kn subscription create](kn_subscription_create.md)	 - Create a subscription
+* [kn subscription delete](kn_subscription_delete.md)	 - Delete a subscription
+* [kn subscription describe](kn_subscription_describe.md)	 - Show details of a subscription
+* [kn subscription list](kn_subscription_list.md)	 - List subscriptions
+* [kn subscription update](kn_subscription_update.md)	 - Update an event subscription
+
diff --git a/docs/cmd/kn_subscription_create.md b/docs/cmd/kn_subscription_create.md
new file mode 100644
index 00000000..a36fcc46
--- /dev/null
+++ b/docs/cmd/kn_subscription_create.md
@@ -0,0 +1,46 @@
+## kn subscription create
+
+Create a subscription
+
+### Synopsis
+
+Create a subscription
+
+```
+kn subscription create NAME
+```
+
+### Examples
+
+```
+
+  # Create a subscription 'sub0' from InMemoryChannel 'pipe0' to a subscriber ksvc 'receiver'
+  kn subscription create sub0 --channel imcv1beta1:pipe0 --sink ksvc:receiver
+
+  # Create a subscription 'sub1' from KafkaChannel 'k1' to ksvc 'mirror', reply to a broker 'nest' and DeadLetterSink to a ksvc 'bucket'
+  kn subscription create sub1 --channel messaging.knative.dev:v1alpha1:KafkaChannel:k1 --sink mirror --sink-reply broker:nest --sink-dead-letter bucket
+```
+
+### Options
+
+```
+      --channel string            Specify the channel to subscribe to. For the default channel, just use the name (e.g. 'mychannel'). A mapped channel type like 'imc' can be used as a prefix (e.g. 'imc:mychannel'). Finally you can specify the full coordinates to the referenced channel with Group:Version:Kind:Name (e.g. 'messaging.knative.dev:v1alpha1:KafkaChannel:mychannel').
+  -h, --help                      help for create
+  -n, --namespace string          Specify the namespace to operate in.
+  -s, --sink string               Addressable sink for events. You can specify a broker, Knative service or URI. Examples: '--sink broker:nest' for a broker 'nest', '--sink https://event.receiver.uri' for an URI with an 'http://' or 'https://' schema, '--sink ksvc:receiver' or simply '--sink receiver' for a Knative service 'receiver'. If a prefix is not provided, it is considered as a Knative service.
+      --sink-dead-letter string   Addressable sink for events. You can specify a broker, Knative service or URI. Examples: '--sink-dead-letter broker:nest' for a broker 'nest', '--sink-dead-letter https://event.receiver.uri' for an URI with an 'http://' or 'https://' schema, '--sink-dead-letter ksvc:receiver' or simply '--sink-dead-letter receiver' for a Knative service 'receiver'. If a prefix is not provided, it is considered as a Knative service.
+      --sink-reply string         Addressable sink for events. You can specify a broker, Knative service or URI. Examples: '--sink-reply broker:nest' for a broker 'nest', '--sink-reply https://event.receiver.uri' for an URI with an 'http://' or 'https://' schema, '--sink-reply ksvc:receiver' or simply '--sink-reply receiver' for a Knative service 'receiver'. If a prefix is not provided, it is considered as a Knative service.
+```
+
+### Options inherited from parent commands
+
+```
+      --config string       kn configuration file (default: ~/.config/kn/config.yaml)
+      --kubeconfig string   kubectl configuration file (default: ~/.kube/config)
+      --log-http            log http traffic
+```
+
+### SEE ALSO
+
+* [kn subscription](kn_subscription.md)	 - Manage event subscriptions
+
diff --git a/docs/cmd/kn_subscription_delete.md b/docs/cmd/kn_subscription_delete.md
new file mode 100644
index 00000000..c173f3aa
--- /dev/null
+++ b/docs/cmd/kn_subscription_delete.md
@@ -0,0 +1,39 @@
+## kn subscription delete
+
+Delete a subscription
+
+### Synopsis
+
+Delete a subscription
+
+```
+kn subscription delete NAME
+```
+
+### Examples
+
+```
+
+  # Delete a subscription 'sub0'
+  kn subscription delete sub0
+```
+
+### Options
+
+```
+  -h, --help               help for delete
+  -n, --namespace string   Specify the namespace to operate in.
+```
+
+### Options inherited from parent commands
+
+```
+      --config string       kn configuration file (default: ~/.config/kn/config.yaml)
+      --kubeconfig string   kubectl configuration file (default: ~/.kube/config)
+      --log-http            log http traffic
+```
+
+### SEE ALSO
+
+* [kn subscription](kn_subscription.md)	 - Manage event subscriptions
+
diff --git a/docs/cmd/kn_subscription_describe.md b/docs/cmd/kn_subscription_describe.md
new file mode 100644
index 00000000..e04c01de
--- /dev/null
+++ b/docs/cmd/kn_subscription_describe.md
@@ -0,0 +1,43 @@
+## kn subscription describe
+
+Show details of a subscription
+
+### Synopsis
+
+Show details of a subscription
+
+```
+kn subscription describe NAME
+```
+
+### Examples
+
+```
+
+  # Describe a subscription 'pipe'
+  kn subscription describe pipe
+```
+
+### Options
+
+```
+      --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 describe
+  -n, --namespace string              Specify the namespace to operate in.
+  -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].
+  -v, --verbose                       More output.
+```
+
+### Options inherited from parent commands
+
+```
+      --config string       kn configuration file (default: ~/.config/kn/config.yaml)
+      --kubeconfig string   kubectl configuration file (default: ~/.kube/config)
+      --log-http            log http traffic
+```
+
+### SEE ALSO
+
+* [kn subscription](kn_subscription.md)	 - Manage event subscriptions
+
diff --git a/docs/cmd/kn_subscription_list.md b/docs/cmd/kn_subscription_list.md
new file mode 100644
index 00000000..4aead93a
--- /dev/null
+++ b/docs/cmd/kn_subscription_list.md
@@ -0,0 +1,47 @@
+## kn subscription list
+
+List subscriptions
+
+### Synopsis
+
+List subscriptions
+
+```
+kn subscription list
+```
+
+### Examples
+
+```
+
+  # List all subscriptions
+  kn subscription list
+
+  # List subscriptions in YAML format
+  kn subscription 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 configuration file (default: ~/.config/kn/config.yaml)
+      --kubeconfig string   kubectl configuration file (default: ~/.kube/config)
+      --log-http            log http traffic
+```
+
+### SEE ALSO
+
+* [kn subscription](kn_subscription.md)	 - Manage event subscriptions
+
diff --git a/docs/cmd/kn_subscription_update.md b/docs/cmd/kn_subscription_update.md
new file mode 100644
index 00000000..3ce6e6cd
--- /dev/null
+++ b/docs/cmd/kn_subscription_update.md
@@ -0,0 +1,45 @@
+## kn subscription update
+
+Update an event subscription
+
+### Synopsis
+
+Update an event subscription
+
+```
+kn subscription update NAME
+```
+
+### Examples
+
+```
+
+  # Update a subscription 'sub0' with a subscriber ksvc 'receiver'
+  kn subscription update sub0 --sink ksvc:receiver
+
+  # Update a subscription 'sub1' with subscriber ksvc 'mirror', reply to a broker 'nest' and DeadLetterSink to a ksvc 'bucket'
+  kn subscription update sub1 --sink mirror --sink-reply broker:nest --sink-dead-letter bucket
+```
+
+### Options
+
+```
+  -h, --help                      help for update
+  -n, --namespace string          Specify the namespace to operate in.
+  -s, --sink string               Addressable sink for events. You can specify a broker, Knative service or URI. Examples: '--sink broker:nest' for a broker 'nest', '--sink https://event.receiver.uri' for an URI with an 'http://' or 'https://' schema, '--sink ksvc:receiver' or simply '--sink receiver' for a Knative service 'receiver'. If a prefix is not provided, it is considered as a Knative service.
+      --sink-dead-letter string   Addressable sink for events. You can specify a broker, Knative service or URI. Examples: '--sink-dead-letter broker:nest' for a broker 'nest', '--sink-dead-letter https://event.receiver.uri' for an URI with an 'http://' or 'https://' schema, '--sink-dead-letter ksvc:receiver' or simply '--sink-dead-letter receiver' for a Knative service 'receiver'. If a prefix is not provided, it is considered as a Knative service.
+      --sink-reply string         Addressable sink for events. You can specify a broker, Knative service or URI. Examples: '--sink-reply broker:nest' for a broker 'nest', '--sink-reply https://event.receiver.uri' for an URI with an 'http://' or 'https://' schema, '--sink-reply ksvc:receiver' or simply '--sink-reply receiver' for a Knative service 'receiver'. If a prefix is not provided, it is considered as a Knative service.
+```
+
+### Options inherited from parent commands
+
+```
+      --config string       kn configuration file (default: ~/.config/kn/config.yaml)
+      --kubeconfig string   kubectl configuration file (default: ~/.kube/config)
+      --log-http            log http traffic
+```
+
+### SEE ALSO
+
+* [kn subscription](kn_subscription.md)	 - Manage event subscriptions
+
diff --git a/docs/cmd/kn_trigger_create.md b/docs/cmd/kn_trigger_create.md
index e5ea45bf..f9c57ed0 100644
--- a/docs/cmd/kn_trigger_create.md
+++ b/docs/cmd/kn_trigger_create.md
@@ -29,7 +29,7 @@ kn trigger create NAME --sink SINK
   -h, --help               help for create
       --inject-broker      Create new broker with name default through common annotation
   -n, --namespace string   Specify the namespace to operate in.
-  -s, --sink string        Addressable sink for events. You can specify a broker, Knative service or URI. Examples: '--sink broker:nest' for a broker 'nest', '--sink https://event.receiver.uri' for an URI with an 'http://' or 'https://' schema, '--sink 'ksvc:receiver' or simply '--sink receiver' for a Knative service 'receiver'. If prefix is not provided, it is considered as a Knative service.
+  -s, --sink string        Addressable sink for events. You can specify a broker, Knative service or URI. Examples: '--sink broker:nest' for a broker 'nest', '--sink https://event.receiver.uri' for an URI with an 'http://' or 'https://' schema, '--sink ksvc:receiver' or simply '--sink receiver' for a Knative service 'receiver'. If a prefix is not provided, it is considered as a Knative service.
 ```
 
 ### Options inherited from parent commands
diff --git a/docs/cmd/kn_trigger_update.md b/docs/cmd/kn_trigger_update.md
index 761bd5cc..7a609489 100644
--- a/docs/cmd/kn_trigger_update.md
+++ b/docs/cmd/kn_trigger_update.md
@@ -33,7 +33,7 @@ kn trigger update NAME
   -h, --help               help for update
       --inject-broker      Create new broker with name default through common annotation
   -n, --namespace string   Specify the namespace to operate in.
-  -s, --sink string        Addressable sink for events. You can specify a broker, Knative service or URI. Examples: '--sink broker:nest' for a broker 'nest', '--sink https://event.receiver.uri' for an URI with an 'http://' or 'https://' schema, '--sink 'ksvc:receiver' or simply '--sink receiver' for a Knative service 'receiver'. If prefix is not provided, it is considered as a Knative service.
+  -s, --sink string        Addressable sink for events. You can specify a broker, Knative service or URI. Examples: '--sink broker:nest' for a broker 'nest', '--sink https://event.receiver.uri' for an URI with an 'http://' or 'https://' schema, '--sink ksvc:receiver' or simply '--sink receiver' for a Knative service 'receiver'. If a prefix is not provided, it is considered as a Knative service.
 ```
 
 ### Options inherited from parent commands
diff --git a/lib/printing/describe.go b/lib/printing/describe.go
new file mode 100644
index 00000000..a130ad64
--- /dev/null
+++ b/lib/printing/describe.go
@@ -0,0 +1,45 @@
+/*
+Copyright 2020 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 printing
+
+import (
+	"fmt"
+
+	"knative.dev/client/pkg/printers"
+	duckv1 "knative.dev/pkg/apis/duck/v1"
+)
+
+// DescribeSink prints the given 'sink' for the given prefix writer 'dw',
+// provide 'attribute' to print the section heading for this sink
+func DescribeSink(dw printers.PrefixWriter, attribute, namespace string, sink *duckv1.Destination) {
+	if sink == nil {
+		return
+	}
+	subWriter := dw.WriteAttribute(attribute, "")
+	ref := sink.Ref
+	if ref != nil {
+		subWriter.WriteAttribute("Name", sink.Ref.Name)
+		if sink.Ref.Namespace != "" && sink.Ref.Namespace != namespace {
+			subWriter.WriteAttribute("Namespace", sink.Ref.Namespace)
+		}
+		subWriter.WriteAttribute("Resource", fmt.Sprintf("%s (%s)", sink.Ref.Kind, sink.Ref.APIVersion))
+	}
+	uri := sink.URI
+	if uri != nil {
+		subWriter.WriteAttribute("URI", uri.String())
+	}
+}
diff --git a/pkg/dynamic/fake/fake.go b/pkg/dynamic/fake/fake.go
index c4c29568..a4529fa5 100644
--- a/pkg/dynamic/fake/fake.go
+++ b/pkg/dynamic/fake/fake.go
@@ -20,6 +20,7 @@ import (
 	dynamicfake "k8s.io/client-go/dynamic/fake"
 
 	eventingv1beta1 "knative.dev/eventing/pkg/apis/eventing/v1beta1"
+	messagingv1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1"
 	servingv1 "knative.dev/serving/pkg/apis/serving/v1"
 
 	"knative.dev/client/pkg/dynamic"
@@ -30,6 +31,7 @@ func CreateFakeKnDynamicClient(testNamespace string, objects ...runtime.Object)
 	scheme := runtime.NewScheme()
 	scheme.AddKnownTypeWithName(schema.GroupVersionKind{Group: "serving.knative.dev", Version: "v1", Kind: "Service"}, &servingv1.Service{})
 	scheme.AddKnownTypeWithName(schema.GroupVersionKind{Group: "eventing.knative.dev", Version: "v1beta1", Kind: "Broker"}, &eventingv1beta1.Broker{})
+	scheme.AddKnownTypeWithName(schema.GroupVersionKind{Group: "eventing.knative.dev", Version: "v1beta1", Kind: "Subscription"}, &messagingv1beta1.Subscription{})
 	client := dynamicfake.NewSimpleDynamicClient(scheme, objects...)
 	return dynamic.NewKnDynamicClient(client, testNamespace)
 }
diff --git a/pkg/kn/commands/channel/create.go b/pkg/kn/commands/channel/create.go
index 145c9b8f..8f5e2251 100644
--- a/pkg/kn/commands/channel/create.go
+++ b/pkg/kn/commands/channel/create.go
@@ -36,8 +36,8 @@ func NewChannelCreateCommand(p *commands.KnParams) *cobra.Command {
   # Create a channel 'pipe' with default setting for channel configuration
   kn channel create pipe
 
-  # Create a channel 'imc1' of type InMemoryChannel using inbuilt alias 'imc'
-  kn channel create imc1 --type imc
+  # Create a channel 'imc1' of type InMemoryChannel using inbuilt alias 'imcv1beta1'
+  kn channel create imc1 --type imcv1beta1
   # same as above without using inbuilt alias but providing explicit GVK
   kn channel create imc1 --type messaging.knative.dev:v1beta1:InMemoryChannel
 
diff --git a/pkg/kn/commands/flags/sink.go b/pkg/kn/commands/flags/sink.go
index a07c4707..c0c950e9 100644
--- a/pkg/kn/commands/flags/sink.go
+++ b/pkg/kn/commands/flags/sink.go
@@ -32,17 +32,21 @@ type SinkFlags struct {
 	sink string
 }
 
-func (i *SinkFlags) Add(cmd *cobra.Command) {
-	cmd.Flags().StringVarP(&i.sink,
-		"sink",
-		"s",
-		"",
-		"Addressable sink for events. "+
-			"You can specify a broker, Knative service or URI. "+
-			"Examples: '--sink broker:nest' for a broker 'nest', "+
-			"'--sink https://event.receiver.uri' for an URI with an 'http://' or 'https://' schema, "+
-			"'--sink 'ksvc:receiver' or simply '--sink receiver' for a Knative service 'receiver'. "+
-			"If prefix is not provided, it is considered as a Knative service.")
+// AddWithFlagName configures sink flag with given flag name and a short flag name
+// pass empty short flag name if you dont want to set one
+func (i *SinkFlags) AddWithFlagName(cmd *cobra.Command, fname, short string) {
+	flag := "--" + fname
+	if short == "" {
+		cmd.Flags().StringVar(&i.sink, fname, "", "")
+	} else {
+		cmd.Flags().StringVarP(&i.sink, fname, short, "", "")
+	}
+	cmd.Flag(fname).Usage = "Addressable sink for events. " +
+		"You can specify a broker, Knative service or URI. " +
+		"Examples: '" + flag + " broker:nest' for a broker 'nest', " +
+		"'" + flag + " https://event.receiver.uri' for an URI with an 'http://' or 'https://' schema, " +
+		"'" + flag + " ksvc:receiver' or simply '" + flag + " receiver' for a Knative service 'receiver'. " +
+		"If a prefix is not provided, it is considered as a Knative service."
 
 	for _, p := range config.GlobalConfig.SinkMappings() {
 		//user configration might override the default configuration
@@ -54,6 +58,11 @@ func (i *SinkFlags) Add(cmd *cobra.Command) {
 	}
 }
 
+// Add configures sink flag with name 'sink' amd short name 's'
+func (i *SinkFlags) Add(cmd *cobra.Command) {
+	i.AddWithFlagName(cmd, "sink", "s")
+}
+
 // sinkPrefixes maps prefixes used for sinks to their GroupVersionResources.
 var sinkMappings = map[string]schema.GroupVersionResource{
 	"broker": {
diff --git a/pkg/kn/commands/subscription/create.go b/pkg/kn/commands/subscription/create.go
new file mode 100644
index 00000000..867555c4
--- /dev/null
+++ b/pkg/kn/commands/subscription/create.go
@@ -0,0 +1,116 @@
+/*
+Copyright 2020 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 subscription
+
+import (
+	"errors"
+	"fmt"
+
+	"github.com/spf13/cobra"
+
+	knerrors "knative.dev/client/pkg/errors"
+	"knative.dev/client/pkg/kn/commands"
+	"knative.dev/client/pkg/kn/commands/flags"
+	knflags "knative.dev/client/pkg/kn/flags"
+	knmessagingv1beta1 "knative.dev/client/pkg/messaging/v1beta1"
+)
+
+// NewSubscriptionCreateCommand to create event subscriptions
+func NewSubscriptionCreateCommand(p *commands.KnParams) *cobra.Command {
+	var (
+		crefFlag                           knflags.ChannelRef
+		subscriberFlag, replyFlag, dlsFlag flags.SinkFlags
+	)
+
+	cmd := &cobra.Command{
+		Use:   "create NAME",
+		Short: "Create a subscription",
+		Example: `
+  # Create a subscription 'sub0' from InMemoryChannel 'pipe0' to a subscriber ksvc 'receiver'
+  kn subscription create sub0 --channel imcv1beta1:pipe0 --sink ksvc:receiver
+
+  # Create a subscription 'sub1' from KafkaChannel 'k1' to ksvc 'mirror', reply to a broker 'nest' and DeadLetterSink to a ksvc 'bucket'
+  kn subscription create sub1 --channel messaging.knative.dev:v1alpha1:KafkaChannel:k1 --sink mirror --sink-reply broker:nest --sink-dead-letter bucket`,
+
+		RunE: func(cmd *cobra.Command, args []string) (err error) {
+			if len(args) != 1 {
+				return errors.New("'kn subscription create' requires the subscription name given as single argument")
+			}
+			name := args[0]
+
+			if crefFlag.Cref == "" {
+				return errors.New("'kn subscription create' requires the channel reference provided with --channel flag")
+			}
+
+			namespace, err := p.GetNamespace(cmd)
+			if err != nil {
+				return err
+			}
+
+			dynamicClient, err := p.NewDynamicClient(namespace)
+			if err != nil {
+				return err
+			}
+
+			client, err := newSubscriptionClient(p, cmd)
+			if err != nil {
+				return err
+			}
+
+			sb := knmessagingv1beta1.NewSubscriptionBuilder(name)
+
+			cref, err := crefFlag.Parse()
+			if err != nil {
+				return err
+			}
+			sb.Channel(cref)
+
+			sub, err := subscriberFlag.ResolveSink(dynamicClient, namespace)
+			if err != nil {
+				return err
+			}
+			sb.Subscriber(sub)
+
+			rep, err := replyFlag.ResolveSink(dynamicClient, namespace)
+			if err != nil {
+				return err
+			}
+			sb.Reply(rep)
+
+			ds, err := dlsFlag.ResolveSink(dynamicClient, namespace)
+			if err != nil {
+				return err
+			}
+			sb.DeadLetterSink(ds)
+
+			err = client.CreateSubscription(sb.Build())
+			if err != nil {
+				return knerrors.GetError(err)
+			}
+
+			fmt.Fprintf(cmd.OutOrStdout(), "Subscription '%s' created in namespace '%s'.\n", name, namespace)
+			return nil
+		},
+	}
+	commands.AddNamespaceFlags(cmd.Flags(), false)
+	crefFlag.Add(cmd.Flags())
+	// add subscriber flag as `--sink`
+	subscriberFlag.Add(cmd)
+	replyFlag.AddWithFlagName(cmd, "sink-reply", "")
+	dlsFlag.AddWithFlagName(cmd, "sink-dead-letter", "")
+	return cmd
+}
diff --git a/pkg/kn/commands/subscription/delete.go b/pkg/kn/commands/subscription/delete.go
new file mode 100644
index 00000000..9fdd0fd7
--- /dev/null
+++ b/pkg/kn/commands/subscription/delete.go
@@ -0,0 +1,57 @@
+/*
+Copyright 2020 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 subscription
+
+import (
+	"errors"
+	"fmt"
+
+	"github.com/spf13/cobra"
+	"knative.dev/client/pkg/kn/commands"
+)
+
+// NewSubscriptionDeleteCommand is for deleting a Subscription
+func NewSubscriptionDeleteCommand(p *commands.KnParams) *cobra.Command {
+	cmd := &cobra.Command{
+		Use:   "delete NAME",
+		Short: "Delete a subscription",
+		Example: `
+  # Delete a subscription 'sub0'
+  kn subscription delete sub0`,
+		RunE: func(cmd *cobra.Command, args []string) error {
+			if len(args) != 1 {
+				return errors.New("'kn subscription delete' requires the subscription name as single argument")
+			}
+			name := args[0]
+
+			subscriptionClient, err := newSubscriptionClient(p, cmd)
+			if err != nil {
+				return err
+			}
+
+			err = subscriptionClient.DeleteSubscription(name)
+			if err != nil {
+				return err
+			}
+
+			fmt.Fprintf(cmd.OutOrStdout(), "Subscription '%s' deleted in namespace '%s'.\n", name, subscriptionClient.Namespace())
+			return nil
+		},
+	}
+	commands.AddNamespaceFlags(cmd.Flags(), false)
+	return cmd
+}
diff --git a/pkg/kn/commands/subscription/describe.go b/pkg/kn/commands/subscription/describe.go
new file mode 100644
index 00000000..4e24bba6
--- /dev/null
+++ b/pkg/kn/commands/subscription/describe.go
@@ -0,0 +1,110 @@
+/*
+Copyright 2020 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 subscription
+
+import (
+	"errors"
+	"fmt"
+
+	"github.com/spf13/cobra"
+
+	"k8s.io/cli-runtime/pkg/genericclioptions"
+	messagingv1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1"
+
+	"knative.dev/client/lib/printing"
+	knerrors "knative.dev/client/pkg/errors"
+	"knative.dev/client/pkg/kn/commands"
+	"knative.dev/client/pkg/printers"
+)
+
+// NewSubscriptionDescribeCommand returns a new command for describe a subscription object
+func NewSubscriptionDescribeCommand(p *commands.KnParams) *cobra.Command {
+
+	// For machine readable output
+	machineReadablePrintFlags := genericclioptions.NewPrintFlags("")
+
+	cmd := &cobra.Command{
+		Use:   "describe NAME",
+		Short: "Show details of a subscription",
+		Example: `
+  # Describe a subscription 'pipe'
+  kn subscription describe pipe`,
+		RunE: func(cmd *cobra.Command, args []string) error {
+			if len(args) != 1 {
+				return errors.New("'kn subscription describe' requires the subscription name given as single argument")
+			}
+			name := args[0]
+
+			client, err := newSubscriptionClient(p, cmd)
+			if err != nil {
+				return err
+			}
+
+			subscription, err := client.GetSubscription(name)
+			if err != nil {
+				return knerrors.GetError(err)
+			}
+
+			out := cmd.OutOrStdout()
+
+			if machineReadablePrintFlags.OutputFlagSpecified() {
+				printer, err := machineReadablePrintFlags.ToPrinter()
+				if err != nil {
+					return err
+				}
+				return printer.PrintObj(subscription, out)
+			}
+
+			dw := printers.NewPrefixWriter(out)
+
+			printDetails, err := cmd.Flags().GetBool("verbose")
+			if err != nil {
+				return err
+			}
+
+			writeSubscription(dw, subscription, printDetails)
+			dw.WriteLine()
+			if err := dw.Flush(); err != nil {
+				return err
+			}
+
+			// Condition info
+			commands.WriteConditions(dw, subscription.Status.Conditions, printDetails)
+			if err := dw.Flush(); err != nil {
+				return err
+			}
+
+			return nil
+		},
+	}
+	flags := cmd.Flags()
+	commands.AddNamespaceFlags(flags, false)
+	flags.BoolP("verbose", "v", false, "More output.")
+	machineReadablePrintFlags.AddFlags(cmd)
+	return cmd
+}
+
+func writeSubscription(dw printers.PrefixWriter, subscription *messagingv1beta1.Subscription, printDetails bool) {
+	commands.WriteMetadata(dw, &subscription.ObjectMeta, printDetails)
+	ctype := fmt.Sprintf("%s:%s (%s)", subscription.Spec.Channel.Kind, subscription.Spec.Channel.Name, subscription.Spec.Channel.APIVersion)
+	dw.WriteAttribute("Channel", ctype)
+	printing.DescribeSink(dw, "Subscriber", subscription.Namespace, subscription.Spec.Subscriber)
+	printing.DescribeSink(dw, "Reply", subscription.Namespace, subscription.Spec.Reply)
+	if subscription.Spec.DeepCopy().Delivery != nil {
+		printing.DescribeSink(dw, "DeadLetterSink", subscription.Namespace, subscription.Spec.Delivery.DeadLetterSink)
+	}
+}
diff --git a/pkg/kn/commands/subscription/flags.go b/pkg/kn/commands/subscription/flags.go
new file mode 100644
index 00000000..d5495b6b
--- /dev/null
+++ b/pkg/kn/commands/subscription/flags.go
@@ -0,0 +1,139 @@
+/*
+Copyright 2020 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 subscription
+
+import (
+	"sort"
+
+	metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1"
+	"k8s.io/apimachinery/pkg/runtime"
+
+	"knative.dev/client/pkg/kn/commands"
+	"knative.dev/client/pkg/kn/commands/flags"
+	hprinters "knative.dev/client/pkg/printers"
+
+	messagingv1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1"
+)
+
+// ListHandlers handles printing human readable table for `kn subscription list` command's output
+func ListHandlers(h hprinters.PrintHandler) {
+	subscriptionColumnDefinitions := []metav1beta1.TableColumnDefinition{
+		{Name: "Namespace", Type: "string", Description: "Namespace of the subscription", Priority: 0},
+		{Name: "Name", Type: "string", Description: "Name of the subscription", Priority: 1},
+		{Name: "Channel", Type: "string", Description: "Channel of the subcription", Priority: 1},
+		{Name: "Subscriber", Type: "string", Description: "Subscriber sink of the subscription", Priority: 1},
+		{Name: "Reply", Type: "string", Description: "Reply sink of the subscription", Priority: 1},
+		{Name: "Dead Letter Sink", Type: "string", Description: "DeadLetterSink of the subscription", Priority: 1},
+		{Name: "Ready", Type: "string", Description: "Ready state of the subscription", Priority: 1},
+		{Name: "Reason", Type: "string", Description: "Reason for non ready subscription", Priority: 1},
+	}
+	h.TableHandler(subscriptionColumnDefinitions, printSubscription)
+	h.TableHandler(subscriptionColumnDefinitions, printSubscriptionList)
+}
+
+// printSubscription populates a single row of Subscription list
+func printSubscription(subscription *messagingv1beta1.Subscription, options hprinters.PrintOptions) ([]metav1beta1.TableRow, error) {
+	row := metav1beta1.TableRow{
+		Object: runtime.RawExtension{Object: subscription},
+	}
+
+	name := subscription.Name
+	ctype := subscription.Spec.Channel.Kind
+	channel := subscription.Spec.Channel.Name
+
+	var subscriber, reply, dls string
+	if subscription.Spec.Subscriber != nil {
+		subscriber = flags.SinkToString(*subscription.Spec.Subscriber)
+	} else {
+		subscriber = ""
+	}
+	if subscription.Spec.Reply != nil {
+		reply = flags.SinkToString(*subscription.Spec.Reply)
+	} else {
+		reply = ""
+	}
+	if subscription.Spec.Delivery != nil && subscription.Spec.Delivery.DeadLetterSink != nil {
+		dls = flags.SinkToString(*subscription.Spec.Delivery.DeadLetterSink)
+	} else {
+		dls = ""
+	}
+	ready := commands.ReadyCondition(subscription.Status.Conditions)
+	reason := commands.NonReadyConditionReason(subscription.Status.Conditions)
+
+	if options.AllNamespaces {
+		row.Cells = append(row.Cells, subscription.Namespace)
+	}
+
+	row.Cells = append(row.Cells, name, ctype+":"+channel, subscriber, reply, dls, ready, reason)
+	return []metav1beta1.TableRow{row}, nil
+}
+
+// printSubscriptionList populates the Subscription list table rows
+func printSubscriptionList(subscriptionList *messagingv1beta1.SubscriptionList, options hprinters.PrintOptions) ([]metav1beta1.TableRow, error) {
+	if options.AllNamespaces {
+		return printSubscriptionListWithNamespace(subscriptionList, options)
+	}
+
+	rows := make([]metav1beta1.TableRow, 0, len(subscriptionList.Items))
+
+	sort.SliceStable(subscriptionList.Items, func(i, j int) bool {
+		return subscriptionList.Items[i].GetName() < subscriptionList.Items[j].GetName()
+	})
+
+	for _, item := range subscriptionList.Items {
+		row, err := printSubscription(&item, options)
+		if err != nil {
+			return nil, err
+		}
+
+		rows = append(rows, row...)
+	}
+	return rows, nil
+}
+
+// printSubscriptionListWithNamespace populates the knative service table rows with namespace column
+func printSubscriptionListWithNamespace(subscriptionList *messagingv1beta1.SubscriptionList, options hprinters.PrintOptions) ([]metav1beta1.TableRow, error) {
+	rows := make([]metav1beta1.TableRow, 0, len(subscriptionList.Items))
+
+	// temporary slice for sorting services in non-default namespace
+	var others []metav1beta1.TableRow
+
+	for _, subscription := range subscriptionList.Items {
+		// Fill in with services in `default` namespace at first
+		if subscription.Namespace == "default" {
+			r, err := printSubscription(&subscription, options)
+			if err != nil {
+				return nil, err
+			}
+			rows = append(rows, r...)
+			continue
+		}
+		// put other services in temporary slice
+		r, err := printSubscription(&subscription, 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/subscription/list.go b/pkg/kn/commands/subscription/list.go
new file mode 100644
index 00000000..8ee749d2
--- /dev/null
+++ b/pkg/kn/commands/subscription/list.go
@@ -0,0 +1,75 @@
+/*
+Copyright 2020 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 subscription
+
+import (
+	"fmt"
+
+	"github.com/spf13/cobra"
+
+	"knative.dev/client/pkg/kn/commands"
+	"knative.dev/client/pkg/kn/commands/flags"
+)
+
+// NewSubscriptionListCommand is for listing subscription objects
+func NewSubscriptionListCommand(p *commands.KnParams) *cobra.Command {
+	listFlags := flags.NewListPrintFlags(ListHandlers)
+
+	listCommand := &cobra.Command{
+		Use:   "list",
+		Short: "List subscriptions",
+		Example: `
+  # List all subscriptions
+  kn subscription list
+
+  # List subscriptions in YAML format
+  kn subscription list -o yaml`,
+
+		RunE: func(cmd *cobra.Command, args []string) (err error) {
+			// TODO: filter list by given subscription name
+
+			client, err := newSubscriptionClient(p, cmd)
+			if err != nil {
+				return err
+			}
+
+			subscriptionList, err := client.ListSubscription()
+			if err != nil {
+				return err
+			}
+
+			if subscriptionList == nil || len(subscriptionList.Items) == 0 {
+				fmt.Fprintf(cmd.OutOrStdout(), "No subscriptions found.\n")
+				return nil
+			}
+
+			if client.Namespace() == "" {
+				listFlags.EnsureWithNamespace()
+			}
+
+			err = listFlags.Print(subscriptionList, 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/subscription/subscription.go b/pkg/kn/commands/subscription/subscription.go
new file mode 100644
index 00000000..ca6bec0c
--- /dev/null
+++ b/pkg/kn/commands/subscription/subscription.go
@@ -0,0 +1,71 @@
+/*
+Copyright 2020 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 subscription
+
+import (
+	"github.com/spf13/cobra"
+
+	"k8s.io/client-go/tools/clientcmd"
+	clientv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1beta1"
+
+	"knative.dev/client/pkg/kn/commands"
+	messagingv1beta1 "knative.dev/client/pkg/messaging/v1beta1"
+)
+
+// NewSubscriptionCommand to manage event subscriptions
+func NewSubscriptionCommand(p *commands.KnParams) *cobra.Command {
+	subscriptionCmd := &cobra.Command{
+		Use:     "subscription COMMAND",
+		Short:   "Manage event subscriptions",
+		Aliases: []string{"subscriptions", "sub"},
+	}
+	subscriptionCmd.AddCommand(NewSubscriptionCreateCommand(p))
+	subscriptionCmd.AddCommand(NewSubscriptionUpdateCommand(p))
+	subscriptionCmd.AddCommand(NewSubscriptionListCommand(p))
+	subscriptionCmd.AddCommand(NewSubscriptionDeleteCommand(p))
+	subscriptionCmd.AddCommand(NewSubscriptionDescribeCommand(p))
+	return subscriptionCmd
+}
+
+var subscriptionClientFactory func(config clientcmd.ClientConfig, namespace string) (messagingv1beta1.KnSubscriptionsClient, error)
+
+func newSubscriptionClient(p *commands.KnParams, cmd *cobra.Command) (messagingv1beta1.KnSubscriptionsClient, error) {
+	namespace, err := p.GetNamespace(cmd)
+	if err != nil {
+		return nil, err
+	}
+
+	if subscriptionClientFactory != nil {
+		config, err := p.GetClientConfig()
+		if err != nil {
+			return nil, err
+		}
+		return subscriptionClientFactory(config, namespace)
+	}
+
+	clientConfig, err := p.RestConfig()
+	if err != nil {
+		return nil, err
+	}
+
+	client, err := clientv1beta1.NewForConfig(clientConfig)
+	if err != nil {
+		return nil, err
+	}
+
+	return messagingv1beta1.NewKnMessagingClient(client, namespace).SubscriptionsClient(), nil
+}
diff --git a/pkg/kn/commands/subscription/update.go b/pkg/kn/commands/subscription/update.go
new file mode 100644
index 00000000..87be5523
--- /dev/null
+++ b/pkg/kn/commands/subscription/update.go
@@ -0,0 +1,105 @@
+/*
+Copyright 2020 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 subscription
+
+import (
+	"errors"
+	"fmt"
+
+	"github.com/spf13/cobra"
+
+	knerrors "knative.dev/client/pkg/errors"
+	"knative.dev/client/pkg/kn/commands"
+	"knative.dev/client/pkg/kn/commands/flags"
+	knmessagingv1beta1 "knative.dev/client/pkg/messaging/v1beta1"
+)
+
+// NewSubscriptionUpdateCommand to update event subscriptions
+func NewSubscriptionUpdateCommand(p *commands.KnParams) *cobra.Command {
+	var subscriberFlag, replyFlag, dlsFlag flags.SinkFlags
+	cmd := &cobra.Command{
+		Use:   "update NAME",
+		Short: "Update an event subscription",
+		Example: `
+  # Update a subscription 'sub0' with a subscriber ksvc 'receiver'
+  kn subscription update sub0 --sink ksvc:receiver
+
+  # Update a subscription 'sub1' with subscriber ksvc 'mirror', reply to a broker 'nest' and DeadLetterSink to a ksvc 'bucket'
+  kn subscription update sub1 --sink mirror --sink-reply broker:nest --sink-dead-letter bucket`,
+
+		RunE: func(cmd *cobra.Command, args []string) (err error) {
+			if len(args) != 1 {
+				return errors.New("'kn subscription update' requires the subscription name given as single argument")
+			}
+			name := args[0]
+
+			namespace, err := p.GetNamespace(cmd)
+			if err != nil {
+				return err
+			}
+
+			dynamicClient, err := p.NewDynamicClient(namespace)
+			if err != nil {
+				return err
+			}
+
+			client, err := newSubscriptionClient(p, cmd)
+			if err != nil {
+				return err
+			}
+
+			foundSub, err := client.GetSubscription(name)
+			if err != nil {
+				return err
+			}
+
+			sb := knmessagingv1beta1.NewSubscriptionBuilderFromExisting(foundSub)
+
+			sub, err := subscriberFlag.ResolveSink(dynamicClient, namespace)
+			if err != nil {
+				return err
+			}
+			sb.Subscriber(sub)
+
+			rep, err := replyFlag.ResolveSink(dynamicClient, namespace)
+			if err != nil {
+				return err
+			}
+			sb.Reply(rep)
+
+			ds, err := dlsFlag.ResolveSink(dynamicClient, namespace)
+			if err != nil {
+				return err
+			}
+			sb.DeadLetterSink(ds)
+
+			err = client.UpdateSubscription(sb.Build())
+			if err != nil {
+				return knerrors.GetError(err)
+			}
+
+			fmt.Fprintf(cmd.OutOrStdout(), "Subscription '%s' updated in namespace '%s'.\n", name, namespace)
+			return nil
+		},
+	}
+	commands.AddNamespaceFlags(cmd.Flags(), false)
+	// add subscriber flag as `--sink`
+	subscriberFlag.Add(cmd)
+	replyFlag.AddWithFlagName(cmd, "sink-reply", "")
+	dlsFlag.AddWithFlagName(cmd, "sink-dead-letter", "")
+	return cmd
+}
diff --git a/pkg/kn/flags/channel_types.go b/pkg/kn/flags/channel_types.go
index 4a5c726a..102476cb 100644
--- a/pkg/kn/flags/channel_types.go
+++ b/pkg/kn/flags/channel_types.go
@@ -19,6 +19,7 @@ import (
 	"strings"
 
 	"github.com/spf13/pflag"
+	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/runtime/schema"
 
 	"knative.dev/client/pkg/kn/config"
@@ -28,6 +29,25 @@ type ChannelTypeFlags struct {
 	ctype string
 }
 
+type ChannelRef struct {
+	Cref string
+}
+
+// ctypeMappings maps aliases used for channel types to their GroupVersionKind
+var ctypeMappings = map[string]schema.GroupVersionKind{
+	"imcv1beta1": {
+		Group:   "messaging.knative.dev",
+		Version: "v1beta1",
+		Kind:    "InMemoryChannel",
+	},
+	"imc": {
+		Group:   "messaging.knative.dev",
+		Version: "v1",
+		Kind:    "InMemoryChannel",
+	},
+}
+
+// Add sets channel type flag definition to given flagset
 func (i *ChannelTypeFlags) Add(f *pflag.FlagSet) {
 	f.StringVar(&i.ctype,
 		"type",
@@ -48,20 +68,7 @@ func (i *ChannelTypeFlags) Add(f *pflag.FlagSet) {
 	}
 }
 
-// ctypeMappings maps aliases used for channel types to their GroupVersionKind
-var ctypeMappings = map[string]schema.GroupVersionKind{
-	"imcv1beta1": {
-		Group:   "messaging.knative.dev",
-		Version: "v1beta1",
-		Kind:    "InMemoryChannel",
-	},
-	"imc": {
-		Group:   "messaging.knative.dev",
-		Version: "v1",
-		Kind:    "InMemoryChannel",
-	},
-}
-
+// Parse parses the CLI value for channel type flag and populates GVK or returns error
 func (i *ChannelTypeFlags) Parse() (*schema.GroupVersionKind, error) {
 	parts := strings.Split(i.ctype, ":")
 	switch len(parts) {
@@ -79,3 +86,38 @@ func (i *ChannelTypeFlags) Parse() (*schema.GroupVersionKind, error) {
 		return nil, fmt.Errorf("Error: incorrect value '%s' for '--type', must be in the format 'Group:Version:Kind' or configure an alias in kn config", i.ctype)
 	}
 }
+
+// Add sets channel reference flag definition to given flagset
+func (i *ChannelRef) Add(f *pflag.FlagSet) {
+	f.StringVar(&i.Cref,
+		"channel",
+		"",
+		"Specify the channel to subscribe to. For the default channel, "+
+			"just use the name (e.g. 'mychannel'). A mapped channel type like 'imc' "+
+			"can be used as a prefix (e.g. 'imc:mychannel'). "+
+			"Finally you can specify the full coordinates to the referenced channel "+
+			"with Group:Version:Kind:Name (e.g. 'messaging.knative.dev:v1alpha1:KafkaChannel:mychannel').")
+}
+
+// Parse parses the CLI value for channel ref flag and populates object reference or return error
+func (i *ChannelRef) Parse() (*corev1.ObjectReference, error) {
+	parts := strings.Split(i.Cref, ":")
+	switch len(parts) {
+	// if no prefix is given, defer to "messaging.knative.dev/v1beta1:Channel"
+	case 1:
+		return &corev1.ObjectReference{Kind: "Channel", APIVersion: "messaging.knative.dev/v1beta1", Name: parts[0]}, nil
+	case 2:
+		if typ, ok := ctypeMappings[parts[0]]; ok {
+			return &corev1.ObjectReference{Kind: typ.Kind, APIVersion: typ.GroupVersion().String(), Name: parts[1]}, nil
+		}
+		return nil, fmt.Errorf("Error: unknown alias '%s' for '--channel', please configure the alias in kn config or specify in the format '--channel Group:Version:Kind:Name'", parts[0])
+	case 4:
+		if parts[0] == "" || parts[1] == "" || parts[2] == "" || parts[3] == "" {
+			return nil, fmt.Errorf("Error: incorrect value '%s' for '--channel', must be in the format 'Group:Version:Kind:Name' or configure an alias in kn config and refer as: '--channel ALIAS:NAME'", i.Cref)
+		}
+		return &corev1.ObjectReference{Kind: parts[2], APIVersion: parts[0] + "/" + parts[1], Name: parts[3]}, nil
+	default:
+		return nil, fmt.Errorf("Error: incorrect value '%s' for '--channel', must be in the format 'Group:Version:Kind:Name' or configure an alias in kn config and refer as: '--channel ALIAS:NAME'", i.Cref)
+	}
+	return nil, nil
+}
diff --git a/pkg/kn/root/root.go b/pkg/kn/root/root.go
index 59b0b32b..96eeb7c0 100644
--- a/pkg/kn/root/root.go
+++ b/pkg/kn/root/root.go
@@ -35,6 +35,7 @@ import (
 	"knative.dev/client/pkg/kn/commands/route"
 	"knative.dev/client/pkg/kn/commands/service"
 	"knative.dev/client/pkg/kn/commands/source"
+	"knative.dev/client/pkg/kn/commands/subscription"
 	"knative.dev/client/pkg/kn/commands/trigger"
 	"knative.dev/client/pkg/kn/commands/version"
 	"knative.dev/client/pkg/kn/config"
@@ -95,6 +96,7 @@ func NewRootCommand(helpFuncs *template.FuncMap) (*cobra.Command, error) {
 				broker.NewBrokerCommand(p),
 				trigger.NewTriggerCommand(p),
 				channel.NewChannelCommand(p),
+				subscription.NewSubscriptionCommand(p),
 			},
 		},
 		{
diff --git a/pkg/messaging/v1beta1/client.go b/pkg/messaging/v1beta1/client.go
index 196a5bf6..9a6c4868 100644
--- a/pkg/messaging/v1beta1/client.go
+++ b/pkg/messaging/v1beta1/client.go
@@ -28,6 +28,9 @@ import (
 type KnMessagingClient interface {
 	// Get the Channels client
 	ChannelsClient() KnChannelsClient
+
+	// Get the Subscriptions client
+	SubscriptionsClient() KnSubscriptionsClient
 }
 
 // messagingClient holds Messaging client interface and namespace
@@ -49,6 +52,11 @@ func (c *messagingClient) ChannelsClient() KnChannelsClient {
 	return newKnChannelsClient(c.client.Channels(c.namespace), c.namespace)
 }
 
+// SubscriptionsClient for working with Subscriptions
+func (c *messagingClient) SubscriptionsClient() KnSubscriptionsClient {
+	return newKnSubscriptionsClient(c.client.Subscriptions(c.namespace), c.namespace)
+}
+
 // update GVK of object
 func updateMessagingGVK(obj runtime.Object) error {
 	return util.UpdateGroupVersionKindWithScheme(obj, messagingv1beta1.SchemeGroupVersion, scheme.Scheme)
diff --git a/pkg/messaging/v1beta1/subscriptions_client.go b/pkg/messaging/v1beta1/subscriptions_client.go
new file mode 100644
index 00000000..ebd3eb1b
--- /dev/null
+++ b/pkg/messaging/v1beta1/subscriptions_client.go
@@ -0,0 +1,191 @@
+/*
+Copyright 2020 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 v1beta1
+
+import (
+	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	eventingduckv1beta1 "knative.dev/eventing/pkg/apis/duck/v1beta1"
+	"knative.dev/eventing/pkg/apis/messaging/v1beta1"
+	clientv1beta1 "knative.dev/eventing/pkg/client/clientset/versioned/typed/messaging/v1beta1"
+	duckv1 "knative.dev/pkg/apis/duck/v1"
+
+	knerrors "knative.dev/client/pkg/errors"
+)
+
+// KnSubscriptionsClient for interacting with Subscriptions
+type KnSubscriptionsClient interface {
+
+	// GetSubscription returns a Subscription by its name
+	GetSubscription(name string) (*v1beta1.Subscription, error)
+
+	// CreteSubscription creates a Subscription with given spec
+	CreateSubscription(subscription *v1beta1.Subscription) error
+
+	// UpdateSubscription updates a Subscription with given spec
+	UpdateSubscription(subscription *v1beta1.Subscription) error
+
+	// DeleteSubscription deletes a Subscription by its name
+	DeleteSubscription(name string) error
+
+	// ListSubscription lists all Subscriptions
+	ListSubscription() (*v1beta1.SubscriptionList, error)
+
+	// Namespace returns the namespace for this subscription client
+	Namespace() string
+}
+
+// subscriptionsClient struct holds the client interface and namespace
+type subscriptionsClient struct {
+	client    clientv1beta1.SubscriptionInterface
+	namespace string
+}
+
+// newKnSubscriptionsClient returns kn subscriptions client
+func newKnSubscriptionsClient(client clientv1beta1.SubscriptionInterface, namespace string) KnSubscriptionsClient {
+	return &subscriptionsClient{
+		client:    client,
+		namespace: namespace,
+	}
+}
+
+// Get the namespace for which this client is created
+func (c *subscriptionsClient) Namespace() string {
+	return c.namespace
+}
+
+// GetSubscription gets Subscription by its name
+func (c *subscriptionsClient) GetSubscription(name string) (*v1beta1.Subscription, error) {
+	subscription, err := c.client.Get(name, metav1.GetOptions{})
+	if err != nil {
+		return nil, knerrors.GetError(err)
+	}
+	err = updateMessagingGVK(subscription)
+	if err != nil {
+		return nil, err
+	}
+	return subscription, nil
+}
+
+// CreateSubscription creates Subscription with given spec
+func (c *subscriptionsClient) CreateSubscription(subscription *v1beta1.Subscription) error {
+	_, err := c.client.Create(subscription)
+	return knerrors.GetError(err)
+}
+
+// UpdateSubscription creates Subscription with given spec
+func (c *subscriptionsClient) UpdateSubscription(subscription *v1beta1.Subscription) error {
+	_, err := c.client.Update(subscription)
+	return knerrors.GetError(err)
+}
+
+// DeleteSubscription deletes Subscription by its name
+func (c *subscriptionsClient) DeleteSubscription(name string) error {
+	return knerrors.GetError(c.client.Delete(name, &metav1.DeleteOptions{}))
+}
+
+// ListSubscription lists subscriptions in configured namespace
+func (c *subscriptionsClient) ListSubscription() (*v1beta1.SubscriptionList, error) {
+	subscriptionList, err := c.client.List(metav1.ListOptions{})
+	if err != nil {
+		return nil, knerrors.GetError(err)
+	}
+
+	return updateSubscriptionListGVK(subscriptionList)
+}
+
+func updateSubscriptionListGVK(subscriptionList *v1beta1.SubscriptionList) (*v1beta1.SubscriptionList, error) {
+	subscriptionListNew := subscriptionList.DeepCopy()
+	err := updateMessagingGVK(subscriptionListNew)
+	if err != nil {
+		return nil, err
+	}
+
+	subscriptionListNew.Items = make([]v1beta1.Subscription, len(subscriptionList.Items))
+	for idx, subscription := range subscriptionList.Items {
+		subscriptionClone := subscription.DeepCopy()
+		err := updateMessagingGVK(subscriptionClone)
+		if err != nil {
+			return nil, err
+		}
+		subscriptionListNew.Items[idx] = *subscriptionClone
+	}
+	return subscriptionListNew, nil
+}
+
+// SubscriptionBuilder is for building the Subscription object
+type SubscriptionBuilder struct {
+	subscription *v1beta1.Subscription
+}
+
+// NewSubscriptionBuilder for building Subscription object
+func NewSubscriptionBuilder(name string) *SubscriptionBuilder {
+	return &SubscriptionBuilder{subscription: &v1beta1.Subscription{
+		ObjectMeta: metav1.ObjectMeta{
+			Name: name,
+		},
+	}}
+}
+
+// NewSubscriptionBuilderFromExisting for building Subscription object from existing Subscription object
+func NewSubscriptionBuilderFromExisting(subs *v1beta1.Subscription) *SubscriptionBuilder {
+	return &SubscriptionBuilder{subscription: subs.DeepCopy()}
+}
+
+// Channel sets the channel reference for this subscription
+func (s *SubscriptionBuilder) Channel(channel *corev1.ObjectReference) *SubscriptionBuilder {
+	if channel == nil {
+		return s
+	}
+
+	s.subscription.Spec.Channel = *channel
+	return s
+}
+
+func (s *SubscriptionBuilder) Subscriber(subs *duckv1.Destination) *SubscriptionBuilder {
+	if subs == nil {
+		return s
+	}
+
+	s.subscription.Spec.Subscriber = subs
+	return s
+}
+
+func (s *SubscriptionBuilder) Reply(reply *duckv1.Destination) *SubscriptionBuilder {
+	if reply == nil {
+		return s
+	}
+
+	s.subscription.Spec.Reply = reply
+	return s
+}
+
+func (s *SubscriptionBuilder) DeadLetterSink(dls *duckv1.Destination) *SubscriptionBuilder {
+	if dls == nil {
+		return s
+	}
+
+	ds := &eventingduckv1beta1.DeliverySpec{}
+	ds.DeadLetterSink = dls
+	s.subscription.Spec.Delivery = ds
+	return s
+}
+
+// Build returns the Subscription object from the builder
+func (s *SubscriptionBuilder) Build() *v1beta1.Subscription {
+	return s.subscription
+}
diff --git a/pkg/messaging/v1beta1/subscriptions_client_mock.go b/pkg/messaging/v1beta1/subscriptions_client_mock.go
new file mode 100644
index 00000000..7123d1da
--- /dev/null
+++ b/pkg/messaging/v1beta1/subscriptions_client_mock.go
@@ -0,0 +1,121 @@
+/*
+Copyright 2020 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 v1beta1
+
+import (
+	"testing"
+
+	"knative.dev/eventing/pkg/apis/messaging/v1beta1"
+
+	"knative.dev/client/pkg/util/mock"
+)
+
+type MockKnSubscriptionsClient struct {
+	t         *testing.T
+	recorder  *SubscriptionsRecorder
+	namespace string
+}
+
+// NewMockKnSubscriptionsClient returns a new mock instance which you need to record for
+func NewMockKnSubscriptionsClient(t *testing.T, ns ...string) *MockKnSubscriptionsClient {
+	namespace := "default"
+	if len(ns) > 0 {
+		namespace = ns[0]
+	}
+	return &MockKnSubscriptionsClient{
+		t:        t,
+		recorder: &SubscriptionsRecorder{mock.NewRecorder(t, namespace)},
+	}
+}
+
+// Ensure that the interface is implemented
+var _ KnSubscriptionsClient = &MockKnSubscriptionsClient{}
+
+// recorder for service
+type SubscriptionsRecorder struct {
+	r *mock.Recorder
+}
+
+// Recorder returns the recorder for registering API calls
+func (c *MockKnSubscriptionsClient) Recorder() *SubscriptionsRecorder {
+	return c.recorder
+}
+
+// Namespace of this client
+func (c *MockKnSubscriptionsClient) Namespace() string {
+	return c.recorder.r.Namespace()
+}
+
+// CreateSubscription records a call for CreateSubscription with the expected error
+func (sr *SubscriptionsRecorder) CreateSubscription(subscription interface{}, err error) {
+	sr.r.Add("CreateSubscription", []interface{}{subscription}, []interface{}{err})
+}
+
+// CreateSubscription performs a previously recorded action, failing if non has been registered
+func (c *MockKnSubscriptionsClient) CreateSubscription(subscription *v1beta1.Subscription) error {
+	call := c.recorder.r.VerifyCall("CreateSubscription", subscription)
+	return mock.ErrorOrNil(call.Result[0])
+}
+
+// GetSubscription records a call for GetSubscription with the expected object or error. Either subscriptions or err should be nil
+func (sr *SubscriptionsRecorder) GetSubscription(name interface{}, subscription *v1beta1.Subscription, err error) {
+	sr.r.Add("GetSubscription", []interface{}{name}, []interface{}{subscription, err})
+}
+
+// GetSubscription performs a previously recorded action, failing if non has been registered
+func (c *MockKnSubscriptionsClient) GetSubscription(name string) (*v1beta1.Subscription, error) {
+	call := c.recorder.r.VerifyCall("GetSubscription", name)
+	return call.Result[0].(*v1beta1.Subscription), mock.ErrorOrNil(call.Result[1])
+}
+
+// DeleteSubscription records a call for DeleteSubscription with the expected error (nil if none)
+func (sr *SubscriptionsRecorder) DeleteSubscription(name interface{}, err error) {
+	sr.r.Add("DeleteSubscription", []interface{}{name}, []interface{}{err})
+}
+
+// DeleteSubscription performs a previously recorded action, failing if non has been registered
+func (c *MockKnSubscriptionsClient) DeleteSubscription(name string) error {
+	call := c.recorder.r.VerifyCall("DeleteSubscription", name)
+	return mock.ErrorOrNil(call.Result[0])
+}
+
+// ListSubscription records a call for ListSubscription with the expected error (nil if none)
+func (sr *SubscriptionsRecorder) ListSubscription(subscriptionsList *v1beta1.SubscriptionList, err error) {
+	sr.r.Add("ListSubscription", []interface{}{}, []interface{}{subscriptionsList, err})
+}
+
+// ListSubscription performs a previously recorded action, failing if non has been registered
+func (c *MockKnSubscriptionsClient) ListSubscription() (*v1beta1.SubscriptionList, error) {
+	call := c.recorder.r.VerifyCall("ListSubscription")
+	return call.Result[0].(*v1beta1.SubscriptionList), mock.ErrorOrNil(call.Result[1])
+}
+
+// UpdateSubscription records a call for CreateSubscription with the expected error
+func (sr *SubscriptionsRecorder) UpdateSubscription(subscription interface{}, err error) {
+	sr.r.Add("UpdateSubscription", []interface{}{subscription}, []interface{}{err})
+}
+
+// UpdateSubscription performs a previously recorded action, failing if non has been registered
+func (c *MockKnSubscriptionsClient) UpdateSubscription(subscription *v1beta1.Subscription) error {
+	call := c.recorder.r.VerifyCall("UpdateSubscription", subscription)
+	return mock.ErrorOrNil(call.Result[0])
+}
+
+// Validates validates whether every recorded action has been called
+func (sr *SubscriptionsRecorder) Validate() {
+	sr.r.CheckThatAllRecordedMethodsHaveBeenCalled()
+}


Test patch:
diff --git a/lib/test/subscription.go b/lib/test/subscription.go
new file mode 100644
index 00000000..08734f6c
--- /dev/null
+++ b/lib/test/subscription.go
@@ -0,0 +1,61 @@
+/*
+Copyright 2020 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 test
+
+import (
+	"gotest.tools/assert"
+
+	"knative.dev/client/pkg/util"
+)
+
+func SubscriptionCreate(r *KnRunResultCollector, sname string, args ...string) {
+	cmd := []string{"subscription", "create", sname}
+	cmd = append(cmd, args...)
+	out := r.KnTest().Kn().Run(cmd...)
+	r.AssertNoError(out)
+	assert.Check(r.T(), util.ContainsAllIgnoreCase(out.Stdout, "subscription", sname, "created"))
+}
+
+func SubscriptionList(r *KnRunResultCollector, args ...string) string {
+	cmd := []string{"subscription", "list"}
+	cmd = append(cmd, args...)
+	out := r.KnTest().Kn().Run(cmd...)
+	r.AssertNoError(out)
+	return out.Stdout
+}
+
+func SubscriptionDescribe(r *KnRunResultCollector, sname string, args ...string) string {
+	cmd := []string{"subscription", "describe", sname}
+	cmd = append(cmd, args...)
+	out := r.KnTest().Kn().Run(cmd...)
+	r.AssertNoError(out)
+	return out.Stdout
+}
+
+func SubscriptionDelete(r *KnRunResultCollector, sname string) {
+	out := r.KnTest().Kn().Run("subscription", "delete", sname)
+	r.AssertNoError(out)
+	assert.Check(r.T(), util.ContainsAllIgnoreCase(out.Stdout, "subscription", sname, "deleted"))
+}
+
+func SubscriptionUpdate(r *KnRunResultCollector, sname string, args ...string) {
+	cmd := []string{"subscription", "update", sname}
+	cmd = append(cmd, args...)
+	out := r.KnTest().Kn().Run(cmd...)
+	r.AssertNoError(out)
+	assert.Check(r.T(), util.ContainsAllIgnoreCase(out.Stdout, "subscription", sname, "updated"))
+}
diff --git a/pkg/kn/commands/flags/sink_test.go b/pkg/kn/commands/flags/sink_test.go
index c3a3e9a9..5a047014 100644
--- a/pkg/kn/commands/flags/sink_test.go
+++ b/pkg/kn/commands/flags/sink_test.go
@@ -17,6 +17,7 @@ package flags
 import (
 	"testing"
 
+	"github.com/spf13/cobra"
 	"gotest.tools/assert"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	eventingv1beta1 "knative.dev/eventing/pkg/apis/eventing/v1beta1"
@@ -33,6 +34,40 @@ type resolveCase struct {
 	errContents string
 }
 
+type sinkFlagAddTestCases struct {
+	flagName          string
+	expectedFlagName  string
+	expectedShortName string
+}
+
+func TestSinkFlagAdd(t *testing.T) {
+	cases := []*sinkFlagAddTestCases{
+		{
+			"",
+			"sink",
+			"s",
+		},
+		{
+			"subscriber",
+			"subscriber",
+			"",
+		},
+	}
+	for _, tc := range cases {
+		c := &cobra.Command{Use: "sinktest"}
+		sinkFlags := new(SinkFlags)
+		if tc.flagName == "" {
+			sinkFlags.Add(c)
+			assert.Equal(t, tc.expectedFlagName, c.Flag("sink").Name)
+			assert.Equal(t, tc.expectedShortName, c.Flag("sink").Shorthand)
+		} else {
+			sinkFlags.AddWithFlagName(c, tc.flagName, "")
+			assert.Equal(t, tc.expectedFlagName, c.Flag(tc.flagName).Name)
+			assert.Equal(t, tc.expectedShortName, c.Flag(tc.flagName).Shorthand)
+		}
+	}
+}
+
 func TestResolve(t *testing.T) {
 	targetExampleCom, err := apis.ParseURL("http://target.example.com")
 	mysvc := &servingv1.Service{
diff --git a/pkg/kn/commands/subscription/create_test.go b/pkg/kn/commands/subscription/create_test.go
new file mode 100644
index 00000000..3073309d
--- /dev/null
+++ b/pkg/kn/commands/subscription/create_test.go
@@ -0,0 +1,82 @@
+/*
+Copyright 2020 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 subscription
+
+import (
+	"testing"
+
+	"gotest.tools/assert"
+	"knative.dev/client/pkg/messaging/v1beta1"
+
+	dynamicfake "knative.dev/client/pkg/dynamic/fake"
+	"knative.dev/client/pkg/util"
+)
+
+func TestCreateSubscriptionErrorCase(t *testing.T) {
+	cClient := v1beta1.NewMockKnSubscriptionsClient(t)
+	dynamicClient := dynamicfake.CreateFakeKnDynamicClient("default")
+
+	cRecorder := cClient.Recorder()
+	_, err := executeSubscriptionCommand(cClient, dynamicClient, "create")
+	assert.Error(t, err, "'kn subscription create' requires the subscription name given as single argument")
+	cRecorder.Validate()
+}
+
+func TestCreateSubscriptionErrorCaseRequiredChannelFlag(t *testing.T) {
+	cClient := v1beta1.NewMockKnSubscriptionsClient(t)
+	dynamicClient := dynamicfake.CreateFakeKnDynamicClient("default")
+
+	cRecorder := cClient.Recorder()
+	_, err := executeSubscriptionCommand(cClient, dynamicClient, "create", "sub0")
+	assert.Error(t, err, "'kn subscription create' requires the channel reference provided with --channel flag")
+	cRecorder.Validate()
+}
+
+func TestCreateSubscriptionErrorCaseChannelFormat(t *testing.T) {
+	cClient := v1beta1.NewMockKnSubscriptionsClient(t)
+	dynamicClient := dynamicfake.CreateFakeKnDynamicClient("default")
+
+	cRecorder := cClient.Recorder()
+	_, err := executeSubscriptionCommand(cClient, dynamicClient, "create", "sub0", "--channel", "foo::bar")
+	assert.Error(t, err, "Error: incorrect value 'foo::bar' for '--channel', must be in the format 'Group:Version:Kind:Name' or configure an alias in kn config and refer as: '--channel ALIAS:NAME'")
+	cRecorder.Validate()
+}
+
+func TestCreateSubscription(t *testing.T) {
+	cClient := v1beta1.NewMockKnSubscriptionsClient(t)
+	dynamicClient := dynamicfake.CreateFakeKnDynamicClient("default",
+		createService("ksvc0"),
+		createBroker("b0"),
+		createBroker("b1"))
+
+	cRecorder := cClient.Recorder()
+	cRecorder.CreateSubscription(createSubscription("sub0",
+		"imc0",
+		"ksvc0",
+		"b0",
+		"b1"),
+		nil)
+
+	out, err := executeSubscriptionCommand(cClient, dynamicClient, "create", "sub0",
+		"--channel", "imcv1beta1:imc0",
+		"--sink", "ksvc0",
+		"--sink-reply", "broker:b0",
+		"--sink-dead-letter", "broker:b1")
+	assert.NilError(t, err, "subscription should be created")
+	assert.Assert(t, util.ContainsAll(out, "created", "sub0", "default"))
+	cRecorder.Validate()
+}
diff --git a/pkg/kn/commands/subscription/delete_test.go b/pkg/kn/commands/subscription/delete_test.go
new file mode 100644
index 00000000..38d1014c
--- /dev/null
+++ b/pkg/kn/commands/subscription/delete_test.go
@@ -0,0 +1,54 @@
+/*
+Copyright 2020 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 subscription
+
+import (
+	"errors"
+	"testing"
+
+	"gotest.tools/assert"
+
+	"knative.dev/client/pkg/messaging/v1beta1"
+	"knative.dev/client/pkg/util"
+)
+
+func TestDeleteSubscriptionErrorCase(t *testing.T) {
+	cClient := v1beta1.NewMockKnSubscriptionsClient(t, "test")
+	cRecorder := cClient.Recorder()
+	_, err := executeSubscriptionCommand(cClient, nil, "delete")
+	assert.Error(t, err, "'kn subscription delete' requires the subscription name as single argument")
+	cRecorder.Validate()
+}
+
+func TestDeleteWithError(t *testing.T) {
+	cClient := v1beta1.NewMockKnSubscriptionsClient(t, "test")
+	cRecorder := cClient.Recorder()
+	cRecorder.DeleteSubscription("sub0", errors.New("not found"))
+	_, err := executeSubscriptionCommand(cClient, nil, "delete", "sub0")
+	assert.ErrorContains(t, err, "not found")
+	cRecorder.Validate()
+}
+
+func TestSubscriptionDelete(t *testing.T) {
+	cClient := v1beta1.NewMockKnSubscriptionsClient(t, "test")
+	cRecorder := cClient.Recorder()
+	cRecorder.DeleteSubscription("sub0", nil)
+	out, err := executeSubscriptionCommand(cClient, nil, "delete", "sub0")
+	assert.NilError(t, err)
+	assert.Assert(t, util.ContainsAll(out, "deleted", "sub0", "test"))
+	cRecorder.Validate()
+}
diff --git a/pkg/kn/commands/subscription/describe_test.go b/pkg/kn/commands/subscription/describe_test.go
new file mode 100644
index 00000000..5f581d6b
--- /dev/null
+++ b/pkg/kn/commands/subscription/describe_test.go
@@ -0,0 +1,59 @@
+/*
+Copyright 2020 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 subscription
+
+import (
+	"errors"
+	"testing"
+
+	"gotest.tools/assert"
+	"knative.dev/client/pkg/messaging/v1beta1"
+
+	"knative.dev/client/pkg/util"
+)
+
+func TestDescribeSubscriptionErrorCase(t *testing.T) {
+	cClient := v1beta1.NewMockKnSubscriptionsClient(t)
+	cRecorder := cClient.Recorder()
+	_, err := executeSubscriptionCommand(cClient, nil, "describe")
+	assert.Error(t, err, "'kn subscription describe' requires the subscription name given as single argument")
+	cRecorder.Validate()
+}
+
+func TestDescribeSubscriptionErrorCaseNotFound(t *testing.T) {
+	cClient := v1beta1.NewMockKnSubscriptionsClient(t)
+	cRecorder := cClient.Recorder()
+	cRecorder.GetSubscription("sub0", nil, errors.New("not found"))
+	_, err := executeSubscriptionCommand(cClient, nil, "describe", "sub0")
+	assert.Error(t, err, "not found")
+	cRecorder.Validate()
+}
+
+func TestDescribeSubscription(t *testing.T) {
+	cClient := v1beta1.NewMockKnSubscriptionsClient(t)
+	cRecorder := cClient.Recorder()
+	cRecorder.GetSubscription("sub0", createSubscription("sub0", "imc0", "ksvc0", "b0", "b1"), nil)
+	out, err := executeSubscriptionCommand(cClient, nil, "describe", "sub0")
+	assert.NilError(t, err, "subscription should be described")
+	assert.Assert(t, util.ContainsAll(out,
+		"sub0",
+		"Channel", "imc0", "messaging.knative.dev", "v1beta1", "InMemoryChannel",
+		"Subscriber", "ksvc0", "serving.knative.dev", "v1", "Service",
+		"Reply", "b0", "eventing.knative.dev", "v1beta1", "Broker",
+		"DeadLetterSink", "b1"))
+	cRecorder.Validate()
+}
diff --git a/pkg/kn/commands/subscription/list_test.go b/pkg/kn/commands/subscription/list_test.go
new file mode 100644
index 00000000..2be6581b
--- /dev/null
+++ b/pkg/kn/commands/subscription/list_test.go
@@ -0,0 +1,71 @@
+/*
+Copyright 2020 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 subscription
+
+import (
+	"strings"
+	"testing"
+
+	"gotest.tools/assert"
+	messagingv1beta1 "knative.dev/eventing/pkg/apis/messaging/v1beta1"
+
+	v1beta1 "knative.dev/client/pkg/messaging/v1beta1"
+	"knative.dev/client/pkg/util"
+)
+
+func TestSubscriptionListNoSubscriptionsFound(t *testing.T) {
+	cClient := v1beta1.NewMockKnSubscriptionsClient(t)
+	cRecorder := cClient.Recorder()
+	cRecorder.ListSubscription(nil, nil)
+	out, err := executeSubscriptionCommand(cClient, nil, "list")
+	assert.NilError(t, err)
+	assert.Check(t, util.ContainsAll(out, "No subscriptions found"))
+	cRecorder.Validate()
+}
+
+func TestSubscriptionList(t *testing.T) {
+	cClient := v1beta1.NewMockKnSubscriptionsClient(t)
+	cRecorder := cClient.Recorder()
+	clist := &messagingv1beta1.SubscriptionList{}
+	clist.Items = []messagingv1beta1.Subscription{
+		*createSubscription("s0", "imc0", "ksvc0", "b00", "b01"),
+		*createSubscription("s1", "imc1", "ksvc1", "b10", "b11"),
+		*createSubscription("s2", "imc2", "ksvc2", "b20", "b21"),
+	}
+
+	t.Run("default list output", func(t *testing.T) {
+		cRecorder.ListSubscription(clist, nil)
+		out, err := executeSubscriptionCommand(cClient, nil, "list")
+		assert.NilError(t, err)
+		ol := strings.Split(out, "\n")
+		assert.Check(t, util.ContainsAll(ol[0], "NAME", "CHANNEL", "SUBSCRIBER", "REPLY", "DEAD LETTER SINK", "READY", "REASON"))
+		assert.Check(t, util.ContainsAll(ol[1], "s0", "InMemoryChannel:imc0", "ksvc:ksvc0", "broker:b00", "broker:b01"))
+		assert.Check(t, util.ContainsAll(ol[2], "s1", "imc1", "ksvc1", "b10", "b11"))
+		assert.Check(t, util.ContainsAll(ol[3], "s2", "imc2", "ksvc2", "b20", "b21"))
+	})
+
+	t.Run("no headers list output", func(t *testing.T) {
+		cRecorder.ListSubscription(clist, nil)
+		out, err := executeSubscriptionCommand(cClient, nil, "list", "--no-headers")
+		assert.NilError(t, err)
+		ol := strings.Split(out, "\n")
+		assert.Check(t, util.ContainsNone(ol[0], "NAME", "CHANNEL", "SUBSCRIBER", "REPLY", "DEAD LETTER SINK", "READY", "REASON"))
+		assert.Check(t, util.ContainsAll(ol[0], "s0", "imc0", "ksvc0", "b00", "b01"))
+	})
+
+	cRecorder.Validate()
+}
diff --git a/pkg/kn/commands/subscription/subscription_test.go b/pkg/kn/commands/subscription/subscription_test.go
new file mode 100644
index 00000000..889fa31b
--- /dev/null
+++ b/pkg/kn/commands/subscription/subscription_test.go
@@ -0,0 +1,147 @@
+/*
+Copyright 2020 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 subscription
+
+import (
+	"bytes"
+
+	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/client-go/tools/clientcmd"
+	eventingv1beta1 "knative.dev/eventing/pkg/apis/eventing/v1beta1"
+	"knative.dev/eventing/pkg/apis/messaging/v1beta1"
+	duckv1 "knative.dev/pkg/apis/duck/v1"
+	servingv1 "knative.dev/serving/pkg/apis/serving/v1"
+
+	kndynamic "knative.dev/client/pkg/dynamic"
+	"knative.dev/client/pkg/kn/commands"
+	clientv1beta1 "knative.dev/client/pkg/messaging/v1beta1"
+)
+
+// Helper methods
+var blankConfig clientcmd.ClientConfig
+
+// TODO: Remove that blankConfig hack for tests in favor of overwriting GetConfig()
+func init() {
+	var err error
+	blankConfig, err = clientcmd.NewClientConfigFromBytes([]byte(`kind: Config
+version: v1
+users:
+- name: u
+clusters:
+- name: c
+  cluster:
+    server: example.com
+contexts:
+- name: x
+  context:
+    user: u
+    cluster: c
+current-context: x
+`))
+	if err != nil {
+		panic(err)
+	}
+}
+
+func executeSubscriptionCommand(subscriptionClient clientv1beta1.KnSubscriptionsClient, dynamicClient kndynamic.KnDynamicClient, args ...string) (string, error) {
+	knParams := &commands.KnParams{}
+	knParams.ClientConfig = blankConfig
+
+	output := new(bytes.Buffer)
+	knParams.Output = output
+	knParams.NewDynamicClient = func(namespace string) (kndynamic.KnDynamicClient, error) {
+		return dynamicClient, nil
+	}
+
+	cmd := NewSubscriptionCommand(knParams)
+	cmd.SetArgs(args)
+	cmd.SetOutput(output)
+
+	subscriptionClientFactory = func(config clientcmd.ClientConfig, namespace string) (clientv1beta1.KnSubscriptionsClient, error) {
+		return subscriptionClient, nil
+	}
+	defer cleanupSubscriptionMockClient()
+
+	err := cmd.Execute()
+
+	return output.String(), err
+}
+
+func cleanupSubscriptionMockClient() {
+	subscriptionClientFactory = nil
+}
+
+func createSubscription(name, channel, subscriber, reply, dls string) *v1beta1.Subscription {
+	return clientv1beta1.
+		NewSubscriptionBuilder(name).
+		Channel(createIMCObjectReference(channel)).
+		Subscriber(createServiceSink(subscriber)).
+		Reply(createBrokerSink(reply)).
+		DeadLetterSink(createBrokerSink(dls)).
+		Build()
+}
+
+func createIMCObjectReference(channel string) *corev1.ObjectReference {
+	return &corev1.ObjectReference{
+		APIVersion: "messaging.knative.dev/v1beta1",
+		Kind:       "InMemoryChannel",
+		Name:       channel,
+	}
+}
+
+func createServiceSink(service string) *duckv1.Destination {
+	if service == "" {
+		return nil
+	}
+	return &duckv1.Destination{
+		Ref: &duckv1.KReference{
+			Kind:       "Service",
+			APIVersion: "serving.knative.dev/v1",
+			Name:       service,
+			Namespace:  "default",
+		},
+	}
+}
+
+func createBrokerSink(broker string) *duckv1.Destination {
+	if broker == "" {
+		return nil
+	}
+	return &duckv1.Destination{
+		Ref: &duckv1.KReference{
+			Kind:       "Broker",
+			APIVersion: "eventing.knative.dev/v1beta1",
+			Name:       broker,
+			Namespace:  "default",
+		},
+	}
+}
+
+func createService(name string) *servingv1.Service {
+	return &servingv1.Service{
+		TypeMeta:   metav1.TypeMeta{Kind: "Service", APIVersion: "serving.knative.dev/v1"},
+		ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: "default"},
+	}
+}
+
+func createBroker(name string) *eventingv1beta1.Broker {
+	return &eventingv1beta1.Broker{
+		TypeMeta:   metav1.TypeMeta{Kind: "Broker", APIVersion: "eventing.knative.dev/v1beta1"},
+		ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: "default"},
+	}
+}
diff --git a/pkg/kn/commands/subscription/update_test.go b/pkg/kn/commands/subscription/update_test.go
new file mode 100644
index 00000000..856de466
--- /dev/null
+++ b/pkg/kn/commands/subscription/update_test.go
@@ -0,0 +1,74 @@
+/*
+Copyright 2020 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 subscription
+
+import (
+	"testing"
+
+	"gotest.tools/assert"
+	"knative.dev/client/pkg/messaging/v1beta1"
+
+	dynamicfake "knative.dev/client/pkg/dynamic/fake"
+	"knative.dev/client/pkg/util"
+)
+
+func TestUpdateSubscriptionErrorCase(t *testing.T) {
+	cClient := v1beta1.NewMockKnSubscriptionsClient(t)
+	dynamicClient := dynamicfake.CreateFakeKnDynamicClient("default")
+
+	cRecorder := cClient.Recorder()
+	_, err := executeSubscriptionCommand(cClient, dynamicClient, "update")
+	assert.Error(t, err, "'kn subscription update' requires the subscription name given as single argument")
+	cRecorder.Validate()
+}
+
+func TestUpdateSubscriptionErrorCaseUnknownChannelFlag(t *testing.T) {
+	cClient := v1beta1.NewMockKnSubscriptionsClient(t)
+	dynamicClient := dynamicfake.CreateFakeKnDynamicClient("default")
+
+	cRecorder := cClient.Recorder()
+	_, err := executeSubscriptionCommand(cClient, dynamicClient, "update", "sub0", "--channel", "imc:i1")
+	assert.Error(t, err, "unknown flag: --channel")
+	cRecorder.Validate()
+}
+
+func TestUpdateSubscription(t *testing.T) {
+	cClient := v1beta1.NewMockKnSubscriptionsClient(t)
+	sub0 := createSubscription("sub0", "imc0", "ksvc0", "", "")
+	dynamicClient := dynamicfake.CreateFakeKnDynamicClient("default",
+		sub0,
+		createService("ksvc1"),
+		createBroker("b0"),
+		createBroker("b1"))
+
+	cRecorder := cClient.Recorder()
+	cRecorder.GetSubscription("sub0", sub0, nil)
+	cRecorder.UpdateSubscription(createSubscription("sub0",
+		"imc0",
+		"ksvc1",
+		"b0",
+		"b1"),
+		nil)
+
+	out, err := executeSubscriptionCommand(cClient, dynamicClient, "update", "sub0",
+		"--sink", "ksvc1",
+		"--sink-reply", "broker:b0",
+		"--sink-dead-letter", "broker:b1")
+	assert.NilError(t, err, "subscription should be updated")
+	assert.Assert(t, util.ContainsAll(out, "updated", "sub0", "default"))
+	cRecorder.Validate()
+}
diff --git a/pkg/kn/flags/channel_types_test.go b/pkg/kn/flags/channel_types_test.go
index 44390194..d38732d1 100644
--- a/pkg/kn/flags/channel_types_test.go
+++ b/pkg/kn/flags/channel_types_test.go
@@ -19,6 +19,7 @@ import (
 
 	"github.com/spf13/pflag"
 	"gotest.tools/assert"
+	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/runtime/schema"
 )
 
@@ -29,6 +30,13 @@ type channelTypeFlagsTestCase struct {
 	expectedErrText string
 }
 
+type channelRefFlagsTestCase struct {
+	name              string
+	arg               string
+	expectedObjectRef *corev1.ObjectReference
+	expectedErrText   string
+}
+
 func TestChannelTypesFlags(t *testing.T) {
 	cases := []*channelTypeFlagsTestCase{
 		{
@@ -82,3 +90,65 @@ func TestChannelTypesFlags(t *testing.T) {
 		}
 	}
 }
+
+func TestChannelRefFlags(t *testing.T) {
+	cases := []*channelRefFlagsTestCase{
+		{
+			"inbuilt alias imcv1beta1 case",
+			"imcv1beta1:i1",
+			&corev1.ObjectReference{APIVersion: "messaging.knative.dev/v1beta1", Kind: "InMemoryChannel", Name: "i1"},
+			"",
+		},
+		{
+			"inbuilt alias 'imc' case",
+			"imc:i2",
+			&corev1.ObjectReference{APIVersion: "messaging.knative.dev/v1", Kind: "InMemoryChannel", Name: "i2"},
+			"",
+		},
+		{
+			"explicit GVK case",
+			"messaging.knative.dev:v1alpha1:KafkaChannel:k1",
+			&corev1.ObjectReference{APIVersion: "messaging.knative.dev/v1alpha1", Kind: "KafkaChannel", Name: "k1"},
+			"",
+		},
+		{
+			"default channel type prefix case",
+			"c1",
+			&corev1.ObjectReference{APIVersion: "messaging.knative.dev/v1beta1", Kind: "Channel", Name: "c1"},
+			"",
+		},
+		{
+			"error case unknown alias",
+			"natss:n1",
+			nil,
+			"Error: unknown alias 'natss' for '--channel', please configure the alias in kn config or specify in the format '--channel Group:Version:Kind:Name'",
+		},
+		{
+			"error case incorrect gvk format, missing version",
+			"foo::bar",
+			nil,
+			"Error: incorrect value 'foo::bar' for '--channel', must be in the format 'Group:Version:Kind:Name' or configure an alias in kn config and refer as: '--channel ALIAS:NAME'",
+		},
+		{
+			"error case incorrect gvk format, additional field",
+			"foo:bar::bat",
+			nil,
+			"Error: incorrect value 'foo:bar::bat' for '--channel', must be in the format 'Group:Version:Kind:Name' or configure an alias in kn config and refer as: '--channel ALIAS:NAME'",
+		},
+	}
+
+	for _, c := range cases {
+		t.Run(c.name, func(t *testing.T) {
+			f := &ChannelRef{}
+			flagset := &pflag.FlagSet{}
+			f.Add(flagset)
+			flagset.Set("channel", c.arg)
+			obj, err := f.Parse()
+			if c.expectedErrText != "" {
+				assert.Equal(t, err.Error(), c.expectedErrText)
+			} else {
+				assert.Equal(t, *obj, *c.expectedObjectRef)
+			}
+		})
+	}
+}
diff --git a/test/e2e/subscription_test.go b/test/e2e/subscription_test.go
new file mode 100644
index 00000000..bc50865d
--- /dev/null
+++ b/test/e2e/subscription_test.go
@@ -0,0 +1,67 @@
+// Copyright 2020 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 im
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// +build e2e
+// +build !serving
+
+package e2e
+
+import (
+	"testing"
+
+	"gotest.tools/assert"
+
+	"knative.dev/client/lib/test"
+	"knative.dev/client/pkg/util"
+)
+
+func TestSubscriptions(t *testing.T) {
+	t.Parallel()
+	it, err := test.NewKnTest()
+	assert.NilError(t, err)
+	defer func() {
+		assert.NilError(t, it.Teardown())
+	}()
+
+	r := test.NewKnRunResultCollector(t, it)
+	defer r.DumpIfFailed()
+
+	t.Log("Create a subscription with all the flags")
+	test.ChannelCreate(r, "c0")
+	test.ServiceCreate(r, "svc0")
+	test.ServiceCreate(r, "svc1")
+	test.ServiceCreate(r, "svc2")
+	test.SubscriptionCreate(r, "sub0", "--channel", "c0", "--sink", "ksvc:svc0", "--sink-reply", "ksvc:svc1", "--sink-dead-letter", "ksvc:svc2")
+
+	t.Log("Update a subscription")
+	test.ServiceCreate(r, "svc3")
+	test.SubscriptionUpdate(r, "sub0", "--sink", "ksvc:svc3")
+
+	t.Log("List subscriptions")
+	slist := test.SubscriptionList(r)
+	assert.Check(t, util.ContainsAll(slist, "NAME", "CHANNEL", "SUBSCRIBER", "REPLY", "DEAD LETTER SINK", "READY", "REASON"))
+	assert.Check(t, util.ContainsAll(slist, "sub0", "c0", "ksvc:svc3", "ksvc:svc1", "ksvc:svc2", "True"))
+
+	t.Log("Describe subscription")
+	sdesc := test.SubscriptionDescribe(r, "sub0")
+	assert.Check(t, util.ContainsAll(sdesc, "sub0", "Age", "Channel", "Channel", "c0", "Subscriber", "svc3", "Resource", "Service", "serving.knative.dev/v1", "Reply", "svc1", "DeadLetterSink", "svc2", "Conditions"))
+
+	t.Log("Delete subscription")
+	test.SubscriptionDelete(r, "sub0")
+	test.ServiceDelete(r, "svc0")
+	test.ServiceDelete(r, "svc1")
+	test.ServiceDelete(r, "svc2")
+	test.ServiceDelete(r, "svc3")
+	test.ChannelDelete(r, "c0")
+}