Repository: knative/client
Pull request #1514 (2021-11-08 08:45:20)

Add --tag flag to service create and allow traffic split <100 when @latest is specified
## Description

Add `--tag` flag to service create and interpret just value arguments to the flag as `@latest=value`
When `@latest` is specified as argument to `--traffic` and sum < 100, calculate the remaining revision

<!-- Please add a short summary about what the pull request is going to bring on the table -->

## Changes

<!-- Please add list of more detailed changes. These changes should be reflected also in the commit messages -->

* The arguments that don't follow `key=value` format and just `value` format will be treated as `@latest=value`
* `service create` will have a `--tag` flag so revision is created with a tag
* Updating traffic split for a service when `@latest` is specified and the total sum is less than 100 for a service with N revisions will work as follows:
     * If the update leads to a new revision creation, total N `key=value` arguments need to be specified for `--traffic`
     *  If the update does not create a new revision, total N-1 `key=value` arguments need to be specified for `--traffic`

## Reference

<!-- Please add the corresponding issue number which this pull request is about to fix -->
Fixes #

<!--
Please add an entry to CHANGELOG.adoc file, too, as part of your Pull Request.

In the following cases, add a short description of PR to the unreleased section in CHANGELOG.adoc:

- 🎁 New feature
- 🐛 Bug fix
- ✨ Feature Update
- 🐣 Refactoring
- 🗑️ Remove feature or internal logic

See other entries in CHANGELOG.adoc as an example for how to add the entry, including a reference to the corresponding issue/PR

PLEASE DON'T ADD THAT LINE HERE IN THE PULL-REQUEST DESCRIPTION BUT DIRECTLY IN CHANGELOG.ADOC AND ADD CHANGELOG.ADOC AS PART OF YOUR PULL-REQUEST.
-->

<!--
To automatically lint go code in this pull request uncomment the line below. You get feedback as comments on your pull request then -->

<!--
/lint
-->


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

This pull-request has been approved by: *<a href="https://github.com/knative/client/pull/1514#" title="Author self-approved">vyasgun</a>*
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please assign **evankanderson** after the PR has been reviewed.
You can assign the PR to them by writing `/assign @evankanderson` in a comment when ready.

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

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

- **[OWNERS](https://github.com/knative/client/blob/main/OWNERS)**

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":["evankanderson"]} -->
knative-metrics-robot: The following is the coverage report on the affected files.
Say `/test pull-knative-client-go-coverage` to re-run this coverage report

File | Old Coverage | New Coverage | Delta
---- |:------------:|:------------:|:-----:
[pkg/kn/commands/service/create.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/1514/pull-knative-client-go-coverage/1457630308865150976/artifacts/line-cov.html#file1) | 87.9% | 84.3% | -3.5
[pkg/kn/traffic/compute.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/1514/pull-knative-client-go-coverage/1457630308865150976/artifacts/line-cov.html#file2) | 100.0% | 99.5% | -0.5

knative-prow-robot: @vyasgun: The following test **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-knative-client-build-tests | 5fddd0e7a584a9748101de43a78977c0b4ce6671 | [link](https://prow.knative.dev/view/gs/knative-prow/pr-logs/pull/knative_client/1514/pull-knative-client-build-tests/1457630308777070592) | true | `/test pull-knative-client-build-tests`

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

<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 -->
codecov[bot]: # [Codecov](https://codecov.io/gh/knative/client/pull/1514?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative) Report
> Merging [#1514](https://codecov.io/gh/knative/client/pull/1514?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative) (5fddd0e) into [main](https://codecov.io/gh/knative/client/commit/09d48d5f4c2fa856f991e02a85f4f3b8c8b3d751?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative) (09d48d5) will **decrease** coverage by `0.02%`.
> The diff coverage is `61.90%`.

[![Impacted file tree graph](https://codecov.io/gh/knative/client/pull/1514/graphs/tree.svg?width=650&height=150&src=pr&token=bkTp6BzJiV&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative)](https://codecov.io/gh/knative/client/pull/1514?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative)

```diff
@@            Coverage Diff             @@
##             main    #1514      +/-   ##
==========================================
- Coverage   79.34%   79.32%   -0.03%     
==========================================
  Files         162      162              
  Lines        8502     8507       +5     
==========================================
+ Hits         6746     6748       +2     
- Misses       1075     1079       +4     
+ Partials      681      680       -1     
```


| [Impacted Files](https://codecov.io/gh/knative/client/pull/1514?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative) | Coverage Δ | |
|---|---|---|
| [pkg/kn/commands/service/create.go](https://codecov.io/gh/knative/client/pull/1514/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative#diff-cGtnL2tuL2NvbW1hbmRzL3NlcnZpY2UvY3JlYXRlLmdv) | `76.11% <25.00%> (-3.25%)` | :arrow_down: |
| [pkg/kn/traffic/compute.go](https://codecov.io/gh/knative/client/pull/1514/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative#diff-cGtnL2tuL3RyYWZmaWMvY29tcHV0ZS5nbw==) | `98.90% <33.33%> (-1.10%)` | :arrow_down: |
| [pkg/kn/commands/flags/traffic.go](https://codecov.io/gh/knative/client/pull/1514/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative#diff-cGtnL2tuL2NvbW1hbmRzL2ZsYWdzL3RyYWZmaWMuZ28=) | `100.00% <100.00%> (ø)` | |
| [pkg/kn/config/config.go](https://codecov.io/gh/knative/client/pull/1514/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative#diff-cGtnL2tuL2NvbmZpZy9jb25maWcuZ28=) | `54.25% <0.00%> (+1.31%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/knative/client/pull/1514?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/knative/client/pull/1514?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative). Last update [09d48d5...5fddd0e](https://codecov.io/gh/knative/client/pull/1514?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative).

knative-metrics-robot: The following is the coverage report on the affected files.
Say `/test pull-knative-client-go-coverage` to re-run this coverage report

File | Old Coverage | New Coverage | Delta
---- |:------------:|:------------:|:-----:
[pkg/kn/commands/service/create.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/1514/pull-knative-client-go-coverage/1457688431210532864/artifacts/line-cov.html#file1) | 87.9% | 84.3% | -3.5
[pkg/kn/traffic/compute.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/1514/pull-knative-client-go-coverage/1457688431210532864/artifacts/line-cov.html#file2) | 100.0% | 99.5% | -0.5

knative-metrics-robot: The following is the coverage report on the affected files.
Say `/test pull-knative-client-go-coverage` to re-run this coverage report

File | Old Coverage | New Coverage | Delta
---- |:------------:|:------------:|:-----:
[pkg/kn/commands/service/create.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/1514/pull-knative-client-go-coverage/1458399087169638400/artifacts/line-cov.html#file1) | 87.9% | 87.8% | -0.0
[pkg/kn/traffic/compute.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/1514/pull-knative-client-go-coverage/1458399087169638400/artifacts/line-cov.html#file2) | 100.0% | 99.5% | -0.5

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

This pull-request has been approved by: *<a href="https://github.com/knative/client/pull/1514#" title="Author self-approved">vyasgun</a>*
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please ask for approval from **maximilien** after the PR has been reviewed.

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

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

- **[OWNERS](https://github.com/knative/client/blob/main/OWNERS)**

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":["maximilien"]} -->
knative-metrics-robot: The following is the coverage report on the affected files.
Say `/test pull-knative-client-go-coverage` to re-run this coverage report

File | Old Coverage | New Coverage | Delta
---- |:------------:|:------------:|:-----:
[pkg/kn/commands/service/create.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/1514/pull-knative-client-go-coverage/1462776728249176064/artifacts/line-cov.html#file1) | 87.9% | 87.8% | -0.0
[pkg/kn/traffic/compute.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/1514/pull-knative-client-go-coverage/1462776728249176064/artifacts/line-cov.html#file3) | 100.0% | 94.6% | -5.4

knative-metrics-robot: The following is the coverage report on the affected files.
Say `/test pull-knative-client-go-coverage` to re-run this coverage report

File | Old Coverage | New Coverage | Delta
---- |:------------:|:------------:|:-----:
[pkg/kn/commands/service/create.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/1514/pull-knative-client-go-coverage/1462815907028930560/artifacts/line-cov.html#file1) | 87.9% | 87.8% | -0.0
[pkg/kn/traffic/compute.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/1514/pull-knative-client-go-coverage/1462815907028930560/artifacts/line-cov.html#file3) | 100.0% | 98.5% | -1.5

knative-metrics-robot: The following is the coverage report on the affected files.
Say `/test pull-knative-client-go-coverage` to re-run this coverage report

File | Old Coverage | New Coverage | Delta
---- |:------------:|:------------:|:-----:
[pkg/kn/commands/service/create.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/1514/pull-knative-client-go-coverage/1462825006995083264/artifacts/line-cov.html#file1) | 87.9% | 88.7% | 0.8
[pkg/kn/traffic/compute.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/1514/pull-knative-client-go-coverage/1462825006995083264/artifacts/line-cov.html#file3) | 100.0% | 99.0% | -1.0

knative-metrics-robot: The following is the coverage report on the affected files.
Say `/test pull-knative-client-go-coverage` to re-run this coverage report

File | Old Coverage | New Coverage | Delta
---- |:------------:|:------------:|:-----:
[pkg/kn/commands/service/create.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/1514/pull-knative-client-go-coverage/1462834521094230016/artifacts/line-cov.html#file1) | 87.9% | 88.7% | 0.8
[pkg/kn/traffic/compute.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/1514/pull-knative-client-go-coverage/1462834521094230016/artifacts/line-cov.html#file3) | 100.0% | 99.0% | -1.0

knative-metrics-robot: The following is the coverage report on the affected files.
Say `/test pull-knative-client-go-coverage` to re-run this coverage report

File | Old Coverage | New Coverage | Delta
---- |:------------:|:------------:|:-----:
[pkg/kn/commands/service/create.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/1514/pull-knative-client-go-coverage/1462840892497858560/artifacts/line-cov.html#file1) | 87.9% | 88.7% | 0.8
[pkg/kn/traffic/compute.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/1514/pull-knative-client-go-coverage/1462840892497858560/artifacts/line-cov.html#file3) | 100.0% | 99.0% | -1.0

knative-metrics-robot: The following is the coverage report on the affected files.
Say `/test pull-knative-client-go-coverage` to re-run this coverage report

File | Old Coverage | New Coverage | Delta
---- |:------------:|:------------:|:-----:
[pkg/kn/commands/service/create.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/1514/pull-knative-client-go-coverage/1463084981327761408/artifacts/line-cov.html#file1) | 87.9% | 88.7% | 0.8
[pkg/kn/traffic/compute.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/1514/pull-knative-client-go-coverage/1463084981327761408/artifacts/line-cov.html#file3) | 100.0% | 99.0% | -1.0

knative-metrics-robot: The following is the coverage report on the affected files.
Say `/test pull-knative-client-go-coverage` to re-run this coverage report

File | Old Coverage | New Coverage | Delta
---- |:------------:|:------------:|:-----:
[pkg/kn/commands/service/create.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/1514/pull-knative-client-go-coverage/1463500788163678208/artifacts/line-cov.html#file1) | 87.9% | 88.7% | 0.8
[pkg/kn/traffic/compute.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/1514/pull-knative-client-go-coverage/1463500788163678208/artifacts/line-cov.html#file3) | 100.0% | 99.0% | -1.0

knative-metrics-robot: The following is the coverage report on the affected files.
Say `/test pull-knative-client-go-coverage` to re-run this coverage report

File | Old Coverage | New Coverage | Delta
---- |:------------:|:------------:|:-----:
[pkg/kn/commands/service/create.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/1514/pull-knative-client-go-coverage/1464209652144148480/artifacts/line-cov.html#file1) | 87.9% | 88.7% | 0.8

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

This pull-request has been approved by: *<a href="https://github.com/knative/client/pull/1514#pullrequestreview-816757101" title="Approved">dsimansk</a>*, *<a href="https://github.com/knative/client/pull/1514#" title="Author self-approved">vyasgun</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/main/OWNERS)~~ [dsimansk]

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-metrics-robot: The following is the coverage report on the affected files.
Say `/test pull-knative-client-go-coverage` to re-run this coverage report

File | Old Coverage | New Coverage | Delta
---- |:------------:|:------------:|:-----:
[pkg/kn/commands/service/create.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/1514/pull-knative-client-go-coverage/1465266322920181760/artifacts/line-cov.html#file1) | 87.9% | 88.7% | 0.8

knative-metrics-robot: The following is the coverage report on the affected files.
Say `/test pull-knative-client-go-coverage` to re-run this coverage report

File | Old Coverage | New Coverage | Delta
---- |:------------:|:------------:|:-----:
[pkg/kn/commands/service/create.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/1514/pull-knative-client-go-coverage/1465288836337635328/artifacts/line-cov.html#file1) | 87.9% | 88.7% | 0.8
[pkg/kn/traffic/compute.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/1514/pull-knative-client-go-coverage/1465288836337635328/artifacts/line-cov.html#file3) | 100.0% | 99.0% | -1.0

knative-metrics-robot: The following is the coverage report on the affected files.
Say `/test pull-knative-client-go-coverage` to re-run this coverage report

File | Old Coverage | New Coverage | Delta
---- |:------------:|:------------:|:-----:
[pkg/kn/commands/service/create.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/1514/pull-knative-client-go-coverage/1465289850662948864/artifacts/line-cov.html#file1) | 87.9% | 88.7% | 0.8
[pkg/kn/traffic/compute.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/1514/pull-knative-client-go-coverage/1465289850662948864/artifacts/line-cov.html#file3) | 100.0% | 99.0% | -1.0

knative-metrics-robot: The following is the coverage report on the affected files.
Say `/test pull-knative-client-go-coverage` to re-run this coverage report

File | Old Coverage | New Coverage | Delta
---- |:------------:|:------------:|:-----:
[pkg/kn/commands/service/create.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/1514/pull-knative-client-go-coverage/1465291785726070784/artifacts/line-cov.html#file1) | 87.9% | 88.7% | 0.8
[pkg/kn/traffic/compute.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/1514/pull-knative-client-go-coverage/1465291785726070784/artifacts/line-cov.html#file3) | 100.0% | 99.0% | -1.0

knative-metrics-robot: The following is the coverage report on the affected files.
Say `/test pull-knative-client-go-coverage` to re-run this coverage report

File | Old Coverage | New Coverage | Delta
---- |:------------:|:------------:|:-----:
[pkg/kn/commands/service/create.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/1514/pull-knative-client-go-coverage/1465294617661411328/artifacts/line-cov.html#file1) | 87.9% | 88.7% | 0.8

knative-metrics-robot: The following is the coverage report on the affected files.
Say `/test pull-knative-client-go-coverage` to re-run this coverage report

File | Old Coverage | New Coverage | Delta
---- |:------------:|:------------:|:-----:
[pkg/kn/commands/service/create.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/1514/pull-knative-client-go-coverage/1465297578600960000/artifacts/line-cov.html#file1) | 87.9% | 88.7% | 0.8

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

This pull-request has been approved by: *<a href="https://github.com/knative/client/pull/1514#pullrequestreview-817798252" title="LGTM">dsimansk</a>*, *<a href="https://github.com/knative/client/pull/1514#" title="Author self-approved">vyasgun</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/main/OWNERS)~~ [dsimansk]

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

Patch:
diff --git a/docs/cmd/kn_service_create.md b/docs/cmd/kn_service_create.md
index 1a414817..33ea8def 100644
--- a/docs/cmd/kn_service_create.md
+++ b/docs/cmd/kn_service_create.md
@@ -92,6 +92,7 @@ kn service create NAME --image IMAGE
       --scale-utilization int             Percentage of concurrent requests utilization before scaling up. (default 70)
       --scale-window string               Duration to look back for making auto-scaling decisions. The service is scaled to zero if no request was received in during that time. (eg: 10s)
       --service-account string            Service account name to set. An empty argument ("") clears the service account. The referenced service account must exist in the service's namespace.
+      --tag strings                       Set tag (format: --tag revisionRef=tagName) where revisionRef can be a revision or '@latest' string representing latest ready revision. This flag can be specified multiple times.
       --target string                     Work on local directory instead of a remote cluster (experimental)
       --user int                          The user ID to run the container (e.g., 1001).
       --volume stringArray                Add a volume from a ConfigMap (prefix cm: or config-map:) or a Secret (prefix secret: or sc:). Example: --volume myvolume=cm:myconfigmap or --volume myvolume=secret:mysecret. You can use this flag multiple times. To unset a ConfigMap/Secret reference, append "-" to the name, e.g. --volume myvolume-.
diff --git a/pkg/kn/commands/flags/traffic.go b/pkg/kn/commands/flags/traffic.go
index 4675e7e5..4e8a085c 100644
--- a/pkg/kn/commands/flags/traffic.go
+++ b/pkg/kn/commands/flags/traffic.go
@@ -25,22 +25,37 @@ type Traffic struct {
 }
 
 func (t *Traffic) Add(cmd *cobra.Command) {
-	cmd.Flags().StringSliceVar(&t.RevisionsPercentages,
-		"traffic",
+	t.AddTrafficFlag(cmd)
+
+	t.AddTagFlag(cmd)
+
+	t.AddUntagFlag(cmd)
+}
+
+// AddUntagFlag adds the flag --untag to the command
+func (t *Traffic) AddUntagFlag(cmd *cobra.Command) {
+	cmd.Flags().StringSliceVar(&t.UntagRevisions,
+		"untag",
 		nil,
-		"Set traffic distribution (format: --traffic revisionRef=percent) where revisionRef can be a revision or a tag or '@latest' string "+
-			"representing latest ready revision. This flag can be given multiple times with percent summing up to 100%.")
+		"Untag revision (format: --untag tagName). This flag can be specified multiple times.")
+}
 
+// AddTagFlag adds the flag --tag to the command
+func (t *Traffic) AddTagFlag(cmd *cobra.Command) {
 	cmd.Flags().StringSliceVar(&t.RevisionsTags,
 		"tag",
 		nil,
 		"Set tag (format: --tag revisionRef=tagName) where revisionRef can be a revision or '@latest' string representing latest ready revision. "+
 			"This flag can be specified multiple times.")
+}
 
-	cmd.Flags().StringSliceVar(&t.UntagRevisions,
-		"untag",
+// AddTrafficFlag adds the flag --traffic to the command
+func (t *Traffic) AddTrafficFlag(cmd *cobra.Command) {
+	cmd.Flags().StringSliceVar(&t.RevisionsPercentages,
+		"traffic",
 		nil,
-		"Untag revision (format: --untag tagName). This flag can be specified multiple times.")
+		"Set traffic distribution (format: --traffic revisionRef=percent) where revisionRef can be a revision or a tag or '@latest' string "+
+			"representing latest ready revision. This flag can be given multiple times with percent summing up to 100%.")
 }
 
 func (t *Traffic) PercentagesChanged(cmd *cobra.Command) bool {
diff --git a/pkg/kn/commands/service/create.go b/pkg/kn/commands/service/create.go
index 161b210b..df52b846 100644
--- a/pkg/kn/commands/service/create.go
+++ b/pkg/kn/commands/service/create.go
@@ -23,6 +23,8 @@ import (
 
 	"knative.dev/client/pkg/config"
 	"knative.dev/client/pkg/kn/commands"
+	"knative.dev/client/pkg/kn/commands/flags"
+	"knative.dev/client/pkg/kn/traffic"
 	servinglib "knative.dev/client/pkg/serving"
 
 	"knative.dev/serving/pkg/apis/serving"
@@ -82,6 +84,7 @@ var create_example = `
 func NewServiceCreateCommand(p *commands.KnParams) *cobra.Command {
 	var editFlags ConfigurationEditFlags
 	var waitFlags commands.WaitFlags
+	var trafficFlags flags.Traffic
 
 	serviceCreateCommand := &cobra.Command{
 		Use:     "create NAME --image IMAGE",
@@ -118,6 +121,15 @@ func NewServiceCreateCommand(p *commands.KnParams) *cobra.Command {
 			if err != nil {
 				return err
 			}
+			if trafficFlags.TagsChanged(cmd) {
+				trafficFlags.RevisionsPercentages = []string{"@latest=100"}
+
+				traffic, err := traffic.Compute(cmd, service, &trafficFlags, nil, editFlags.AnyMutation(cmd))
+				if err != nil {
+					return err
+				}
+				service.Spec.Traffic = traffic
+			}
 			serviceExists, err := serviceExists(cmd.Context(), client, service.Name)
 			if err != nil {
 				return err
@@ -143,6 +155,7 @@ func NewServiceCreateCommand(p *commands.KnParams) *cobra.Command {
 	commands.AddNamespaceFlags(serviceCreateCommand.Flags(), false)
 	commands.AddGitOpsFlags(serviceCreateCommand.Flags())
 	editFlags.AddCreateFlags(serviceCreateCommand)
+	trafficFlags.AddTagFlag(serviceCreateCommand)
 	waitFlags.AddConditionWaitFlags(serviceCreateCommand, commands.WaitDefaultTimeout, "create", "service", "ready")
 	return serviceCreateCommand
 }
diff --git a/pkg/kn/commands/service/update.go b/pkg/kn/commands/service/update.go
index 393fd850..7619d1f4 100644
--- a/pkg/kn/commands/service/update.go
+++ b/pkg/kn/commands/service/update.go
@@ -107,7 +107,7 @@ func NewServiceUpdateCommand(p *commands.KnParams) *cobra.Command {
 					if err != nil {
 						return nil, err
 					}
-					traffic, err := traffic.Compute(cmd, service.Spec.Traffic, &trafficFlags, service.Name, revisions.Items)
+					traffic, err := traffic.Compute(cmd, service, &trafficFlags, revisions.Items, editFlags.AnyMutation(cmd))
 					if err != nil {
 						return nil, err
 					}
diff --git a/pkg/kn/traffic/compute.go b/pkg/kn/traffic/compute.go
index 17c26010..fae87ef5 100644
--- a/pkg/kn/traffic/compute.go
+++ b/pkg/kn/traffic/compute.go
@@ -31,7 +31,6 @@ var latestRevisionRef = "@latest"
 
 const (
 	errorDistributionRevisionCount = iota
-	errorDistributionLatestTag
 	errorDistributionRevisionNotFound
 )
 
@@ -44,6 +43,9 @@ func newServiceTraffic(traffic []servingv1.TrafficTarget) ServiceTraffic {
 
 func splitByEqualSign(pair string) (string, string, error) {
 	parts := strings.Split(pair, "=")
+	if len(parts) == 1 {
+		return latestRevisionRef, parts[0], nil
+	}
 	if len(parts) != 2 || parts[0] == "" || parts[1] == "" {
 		return "", "", fmt.Errorf("expecting the value format in value1=value2, given %s", pair)
 	}
@@ -224,12 +226,10 @@ func errorTrafficDistribution(sum int, reason int) error {
 	switch reason {
 	case errorDistributionRevisionCount:
 		errMsg = "incorrect number of revisions specified. Only 1 revision should be missing"
-	case errorDistributionLatestTag:
-		errMsg = "cannot determine traffic split when @latest tag is specified"
 	case errorDistributionRevisionNotFound:
 		errMsg = "cannot determine the missing revision"
 	}
-	return fmt.Errorf("unable to allocate the remaining traffic %d. %s", 100-sum, errMsg)
+	return fmt.Errorf("unable to allocate the remaining traffic: %d%%. Reason: %s", 100-sum, errMsg)
 }
 
 func errorSumGreaterThan100(sum int) error {
@@ -240,12 +240,14 @@ func errorSumGreaterThan100(sum int) error {
 // verifyInput checks:
 // - if user has repeated @latest field in --tag or --traffic flags
 // - if provided traffic portion are integers
-func verifyInput(trafficFlags *flags.Traffic, revisions []servingv1.Revision) error {
+// - if traffic as per flags sums to 100
+// - if traffic as per flags < 100, can remaining traffic be automatically directed
+func verifyInput(trafficFlags *flags.Traffic, svc *servingv1.Service, revisions []servingv1.Revision, mutation bool) error {
 	// check if traffic is being sent to @latest tag
 	var latestRefTraffic bool
 
-	// number of revisions
-	var revisionCount = len(revisions)
+	// number of existing revisions
+	var existingRevisionCount = len(revisions)
 
 	err := verifyLatestTag(trafficFlags)
 	if err != nil {
@@ -257,6 +259,14 @@ func verifyInput(trafficFlags *flags.Traffic, revisions []servingv1.Revision) er
 		return err
 	}
 
+	// further verification is not required if sum >= 100
+	if sum == 100 {
+		return nil
+	}
+	if sum > 100 {
+		return errorSumGreaterThan100(sum)
+	}
+
 	if _, ok := revisionRefMap[latestRevisionRef]; ok {
 		// traffic has been routed to @latest tag
 		latestRefTraffic = true
@@ -264,29 +274,47 @@ func verifyInput(trafficFlags *flags.Traffic, revisions []servingv1.Revision) er
 
 	// number of revisions specified in traffic flags
 	specRevPercentCount := len(trafficFlags.RevisionsPercentages)
-	// equivalent check for `cmd.Flags().Changed("traffic")` as we don't have `cmd` in this function
-	if specRevPercentCount > 0 {
-		if sum > 100 {
-			return errorSumGreaterThan100(sum)
+
+	// no traffic to route
+	if specRevPercentCount == 0 {
+		return nil
+	}
+
+	// cannot determine remaining revision. Only 1 should be left out
+	if specRevPercentCount < existingRevisionCount-1 {
+		return errorTrafficDistribution(sum, errorDistributionRevisionCount)
+	}
+
+	// if mutation is set, a new revision will be created after service update.
+	// specRevPercentCount should be equal to existingRevisionCount
+	if mutation {
+		if specRevPercentCount != existingRevisionCount {
+			return errorTrafficDistribution(sum, errorDistributionRevisionCount)
 		}
-		if sum < 100 && specRevPercentCount != revisionCount-1 {
+		if _, ok := revisionRefMap[latestRevisionRef]; !ok {
+			// remaining % can only go to the @latest tag
+			trafficFlags.RevisionsPercentages = append(trafficFlags.RevisionsPercentages, fmt.Sprintf("%s=%d", latestRevisionRef, 100-sum))
+			return nil
+		}
+	} else {
+		// if mutation is not set, specRevPercentCount should be equal to existingRevisionCount
+		if specRevPercentCount != existingRevisionCount-1 {
 			return errorTrafficDistribution(sum, errorDistributionRevisionCount)
 		}
-		if sum < 100 && specRevPercentCount == revisionCount-1 {
-			if latestRefTraffic {
-				return errorTrafficDistribution(sum, errorDistributionLatestTag)
-			}
-			for _, rev := range revisions {
-				if !checkRevisionPresent(revisionRefMap, rev) {
-					trafficFlags.RevisionsPercentages = append(trafficFlags.RevisionsPercentages, fmt.Sprintf("%s=%d", rev.Name, 100-sum))
-					return nil
-				}
-			}
-			return errorTrafficDistribution(sum, errorDistributionRevisionNotFound)
+		if latestRefTraffic {
+			revisionRefMap[svc.Status.LatestReadyRevisionName] = 0
 		}
 	}
 
-	return nil
+	// remaining % to 100
+	for _, rev := range revisions {
+		if !checkRevisionPresent(revisionRefMap, rev) {
+			trafficFlags.RevisionsPercentages = append(trafficFlags.RevisionsPercentages, fmt.Sprintf("%s=%d", rev.Name, 100-sum))
+			return nil
+		}
+	}
+
+	return errorTrafficDistribution(sum, errorDistributionRevisionNotFound)
 }
 
 func verifyRevisionSumAndReferences(trafficFlags *flags.Traffic) (revisionRefMap map[string]int, sum int, err error) {
@@ -352,10 +380,14 @@ func checkRevisionPresent(refMap map[string]int, rev servingv1.Revision) bool {
 	return tagExists || nameExists
 }
 
-// Compute takes service traffic targets and updates per given traffic flags
-func Compute(cmd *cobra.Command, targets []servingv1.TrafficTarget,
-	trafficFlags *flags.Traffic, serviceName string, revisions []servingv1.Revision) ([]servingv1.TrafficTarget, error) {
-	err := verifyInput(trafficFlags, revisions)
+// Compute takes service object, computes traffic per given traffic flags and returns the new traffic. If
+// total traffic per flags < 100, the params 'revisions' and 'mutation' are used to direct remaining
+// traffic. Param 'mutation' is set to true if a new revision will be created on service update
+func Compute(cmd *cobra.Command, svc *servingv1.Service,
+	trafficFlags *flags.Traffic, revisions []servingv1.Revision, mutation bool) ([]servingv1.TrafficTarget, error) {
+	targets := svc.Spec.Traffic
+	serviceName := svc.Name
+	err := verifyInput(trafficFlags, svc, revisions, mutation)
 	if err != nil {
 		return nil, err
 	}
@@ -416,7 +448,7 @@ func Compute(cmd *cobra.Command, targets []servingv1.TrafficTarget,
 		traffic = traffic.TagRevision(tag, revision)
 	}
 
-	if cmd.Flags().Changed("traffic") {
+	if cmd.Flags().Changed("traffic") || (cmd.Name() == "create" && len(trafficFlags.RevisionsTags) > 0) {
 		// reset existing traffic portions as what's on CLI is desired state of traffic split portions
 		traffic.ResetAllTargetPercent()
 


Test patch:
diff --git a/pkg/kn/commands/service/create_test.go b/pkg/kn/commands/service/create_test.go
index 3e2d3143..1a938851 100644
--- a/pkg/kn/commands/service/create_test.go
+++ b/pkg/kn/commands/service/create_test.go
@@ -1084,3 +1084,18 @@ func TestServiceCreateFromYAMLWithOverrideError(t *testing.T) {
 	assert.Assert(t, err != nil)
 	assert.Assert(t, util.ContainsAll(err.Error(), "expected", "0", "<=", "2147483647", autoscaling.MaxScaleAnnotationKey))
 }
+
+func TestServiceCreateTag(t *testing.T) {
+	action, created, _, err := fakeServiceCreate([]string{
+		"service", "create", "foo", "--image", "gcr.io/foo/bar:baz", "--tag", "foo"}, false)
+	assert.NilError(t, err)
+	assert.Assert(t, action.Matches("create", "services"))
+	assert.Equal(t, len(created.Spec.Traffic), 1)
+	assert.Equal(t, created.Spec.Traffic[0].Tag, "foo")
+}
+
+func TestServiceCreateTagWithError(t *testing.T) {
+	_, _, _, err := fakeServiceCreate([]string{
+		"service", "create", "foo", "--image", "gcr.io/foo/bar:baz", "--tag", "foo,bar"}, false)
+	assert.Error(t, err, "repetition of identifier @latest is not allowed, use only once with --tag flag")
+}
diff --git a/pkg/kn/traffic/compute_test.go b/pkg/kn/traffic/compute_test.go
index d0e1a60f..5ffce1ed 100644
--- a/pkg/kn/traffic/compute_test.go
+++ b/pkg/kn/traffic/compute_test.go
@@ -16,6 +16,7 @@ package traffic
 
 import (
 	"gotest.tools/v3/assert"
+	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"knative.dev/client/pkg/kn/commands/revision"
 	servingv1 "knative.dev/serving/pkg/apis/serving/v1"
@@ -35,6 +36,8 @@ type trafficTestCase struct {
 	desiredTags       []string
 	desiredPercents   []int64
 	existingRevisions []servingv1.Revision
+	mutation          bool
+	latestRevision    string
 }
 
 type trafficErrorTestCase struct {
@@ -43,6 +46,8 @@ type trafficErrorTestCase struct {
 	inputFlags        []string
 	errMsg            string
 	existingRevisions []servingv1.Revision
+	mutation          bool
+	latestRevision    string
 }
 
 func newTestTrafficCommand() (*cobra.Command, *flags.Traffic) {
@@ -56,6 +61,30 @@ func newTestTrafficCommand() (*cobra.Command, *flags.Traffic) {
 	return trafficCmd, &trafficFlags
 }
 
+func getService(name, latestRevision string, existingTraffic ServiceTraffic) *servingv1.Service {
+	service := &servingv1.Service{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      name,
+			Namespace: "default",
+		},
+		Spec: servingv1.ServiceSpec{},
+	}
+
+	service.Spec.Template = servingv1.RevisionTemplateSpec{
+		Spec: servingv1.RevisionSpec{},
+	}
+
+	service.Spec.Traffic = existingTraffic
+	service.Spec.Template.Spec.Containers = []corev1.Container{{
+		Resources: corev1.ResourceRequirements{
+			Limits:   corev1.ResourceList{},
+			Requests: corev1.ResourceList{},
+		},
+	}}
+	service.Status.LatestReadyRevisionName = latestRevision
+	return service
+}
+
 func TestCompute(t *testing.T) {
 	for _, testCase := range []trafficTestCase{
 		{
@@ -66,6 +95,14 @@ func TestCompute(t *testing.T) {
 			desiredTags:      []string{"latest"},
 			desiredPercents:  []int64{100},
 		},
+		{
+			name:             "assign 'latest' tag to @latest revision without specifying key",
+			existingTraffic:  append(newServiceTraffic([]servingv1.TrafficTarget{}), newTarget("", "", 100, true)),
+			inputFlags:       []string{"--tag", "latest"},
+			desiredRevisions: []string{"@latest"},
+			desiredTags:      []string{"latest"},
+			desiredPercents:  []int64{100},
+		},
 		{
 			name:             "assign tag to revision",
 			existingTraffic:  append(newServiceTraffic([]servingv1.TrafficTarget{}), newTarget("", "echo-v1", 100, false)),
@@ -217,6 +254,102 @@ func TestCompute(t *testing.T) {
 				},
 			}},
 		},
+		{
+			name:             "traffic split sum < 100 with @latest which mutates service should specify N revs",
+			existingTraffic:  append(newServiceTraffic([]servingv1.TrafficTarget{}), newTarget("", "rev-00001", 0, false), newTarget("", "rev-00002", 0, false), newTarget("", "rev-00003", 100, true)),
+			inputFlags:       []string{"--traffic", "rev-00001=10,rev-00003=40,@latest=20"},
+			desiredRevisions: []string{"rev-00001", "rev-00002", "", "rev-00003"},
+			desiredPercents:  []int64{10, 30, 20, 40},
+			desiredTags:      []string{"", "", "", ""},
+			existingRevisions: []servingv1.Revision{{
+				ObjectMeta: metav1.ObjectMeta{
+					Name: "rev-00001",
+					Labels: map[string]string{
+						"serving.knative.dev/service": "serviceName",
+					},
+				},
+			}, {
+				ObjectMeta: metav1.ObjectMeta{
+					Name: "rev-00002",
+					Labels: map[string]string{
+						"serving.knative.dev/service": "serviceName",
+					},
+				},
+			}, {
+				ObjectMeta: metav1.ObjectMeta{
+					Name: "rev-00003",
+					Labels: map[string]string{
+						"serving.knative.dev/service": "serviceName",
+					},
+				},
+			}},
+			mutation:       true,
+			latestRevision: "rev-00003",
+		},
+		{
+			name:             "traffic split sum < 100 with @latest and does not mutate the service should specify N-1 revs",
+			existingTraffic:  append(newServiceTraffic([]servingv1.TrafficTarget{}), newTarget("", "rev-00001", 0, false), newTarget("", "rev-00002", 0, false), newTarget("", "rev-00003", 100, true)),
+			inputFlags:       []string{"--traffic", "rev-00001=10,@latest=20"},
+			desiredRevisions: []string{"rev-00001", "rev-00002", ""},
+			desiredPercents:  []int64{10, 70, 20},
+			desiredTags:      []string{"", "", ""},
+			existingRevisions: []servingv1.Revision{{
+				ObjectMeta: metav1.ObjectMeta{
+					Name: "rev-00001",
+					Labels: map[string]string{
+						"serving.knative.dev/service": "serviceName",
+					},
+				},
+			}, {
+				ObjectMeta: metav1.ObjectMeta{
+					Name: "rev-00002",
+					Labels: map[string]string{
+						"serving.knative.dev/service": "serviceName",
+					},
+				},
+			}, {
+				ObjectMeta: metav1.ObjectMeta{
+					Name: "rev-00003",
+					Labels: map[string]string{
+						"serving.knative.dev/service": "serviceName",
+					},
+				},
+			}},
+			mutation:       false,
+			latestRevision: "rev-00003",
+		},
+		{
+			name:             "traffic split sum < 100 without which mutates service should specify N revs. Remaining should go to @latest",
+			existingTraffic:  append(newServiceTraffic([]servingv1.TrafficTarget{}), newTarget("", "rev-00001", 0, false), newTarget("", "rev-00002", 0, false), newTarget("", "rev-00003", 100, true)),
+			inputFlags:       []string{"--traffic", "rev-00001=10,rev-00003=40,rev-00002=30"},
+			desiredRevisions: []string{"rev-00001", "rev-00002", "", "rev-00003"},
+			desiredPercents:  []int64{10, 30, 20, 40},
+			desiredTags:      []string{"", "", "", ""},
+			existingRevisions: []servingv1.Revision{{
+				ObjectMeta: metav1.ObjectMeta{
+					Name: "rev-00001",
+					Labels: map[string]string{
+						"serving.knative.dev/service": "serviceName",
+					},
+				},
+			}, {
+				ObjectMeta: metav1.ObjectMeta{
+					Name: "rev-00002",
+					Labels: map[string]string{
+						"serving.knative.dev/service": "serviceName",
+					},
+				},
+			}, {
+				ObjectMeta: metav1.ObjectMeta{
+					Name: "rev-00003",
+					Labels: map[string]string{
+						"serving.knative.dev/service": "serviceName",
+					},
+				},
+			}},
+			mutation:       true,
+			latestRevision: "rev-00003",
+		},
 	} {
 		t.Run(testCase.name, func(t *testing.T) {
 			if lper, lrev, ltag := len(testCase.desiredPercents), len(testCase.desiredRevisions), len(testCase.desiredTags); lper != lrev || lper != ltag {
@@ -227,7 +360,8 @@ func TestCompute(t *testing.T) {
 			testCmd, tFlags := newTestTrafficCommand()
 			testCmd.SetArgs(testCase.inputFlags)
 			testCmd.Execute()
-			targets, err := Compute(testCmd, testCase.existingTraffic, tFlags, "serviceName", testCase.existingRevisions)
+			svc := getService("serviceName", testCase.latestRevision, testCase.existingTraffic)
+			targets, err := Compute(testCmd, svc, tFlags, testCase.existingRevisions, testCase.mutation)
 			if err != nil {
 				t.Fatal(err)
 			}
@@ -270,6 +404,12 @@ func TestComputeErrMsg(t *testing.T) {
 			inputFlags:      []string{"--tag", "@latest=latest,@latest=2"},
 			errMsg:          "repetition of identifier @latest is not allowed, use only once with --tag flag",
 		},
+		{
+			name:            "repeatedly tagging to @latest revision not allowed, without key",
+			existingTraffic: append(newServiceTraffic([]servingv1.TrafficTarget{}), newTarget("", "", 100, true)),
+			inputFlags:      []string{"--tag", "latest,current"},
+			errMsg:          "repetition of identifier @latest is not allowed, use only once with --tag flag",
+		},
 		{
 			name:            "overwriting tag not allowed, to @latest from other revision",
 			existingTraffic: append(append(newServiceTraffic([]servingv1.TrafficTarget{}), newTarget("latest", "", 2, true)), newTarget("stable", "echo-v2", 98, false)),
@@ -353,10 +493,39 @@ func TestComputeErrMsg(t *testing.T) {
 			}},
 		},
 		{
-			name:            "traffic split sum < 100 should not have @latest specified",
+			name:            "traffic split sum < 100 with @latest which mutates service should specify N revs",
 			existingTraffic: append(newServiceTraffic([]servingv1.TrafficTarget{}), newTarget("", "rev-00001", 0, false), newTarget("", "rev-00002", 0, false), newTarget("", "rev-00003", 100, true)),
 			inputFlags:      []string{"--traffic", "rev-00001=10,@latest=20"},
-			errMsg:          errorTrafficDistribution(30, errorDistributionLatestTag).Error(),
+			errMsg:          errorTrafficDistribution(30, errorDistributionRevisionCount).Error(),
+			existingRevisions: []servingv1.Revision{{
+				ObjectMeta: metav1.ObjectMeta{
+					Name: "rev-00001",
+					Labels: map[string]string{
+						"serving.knative.dev/service": "serviceName",
+					},
+				},
+			}, {
+				ObjectMeta: metav1.ObjectMeta{
+					Name: "rev-00002",
+					Labels: map[string]string{
+						"serving.knative.dev/service": "serviceName",
+					},
+				},
+			}, {
+				ObjectMeta: metav1.ObjectMeta{
+					Name: "rev-00003",
+					Labels: map[string]string{
+						"serving.knative.dev/service": "serviceName",
+					},
+				},
+			}},
+			mutation: true,
+		},
+		{
+			name:            "traffic split sum < 100 with @latest and mutates the service should specify N revs",
+			existingTraffic: append(newServiceTraffic([]servingv1.TrafficTarget{}), newTarget("", "rev-00001", 0, false), newTarget("", "rev-00002", 0, false), newTarget("", "rev-00003", 100, true)),
+			inputFlags:      []string{"--traffic", "rev-00001=10,rev-00002=10,@latest=20"},
+			errMsg:          errorTrafficDistribution(40, errorDistributionRevisionCount).Error(),
 			existingRevisions: []servingv1.Revision{{
 				ObjectMeta: metav1.ObjectMeta{
 					Name: "rev-00001",
@@ -379,6 +548,7 @@ func TestComputeErrMsg(t *testing.T) {
 					},
 				},
 			}},
+			mutation: false,
 		},
 		{
 			name:            "traffic split sum < 100 error when remaining revision not found",
@@ -416,7 +586,8 @@ func TestComputeErrMsg(t *testing.T) {
 			testCmd, tFlags := newTestTrafficCommand()
 			testCmd.SetArgs(testCase.inputFlags)
 			testCmd.Execute()
-			_, err := Compute(testCmd, testCase.existingTraffic, tFlags, "serviceName", testCase.existingRevisions)
+			svc := getService("serviceName", testCase.latestRevision, testCase.existingTraffic)
+			_, err := Compute(testCmd, svc, tFlags, testCase.existingRevisions, testCase.mutation)
 			assert.Error(t, err, testCase.errMsg)
 		})
 	}
diff --git a/test/e2e/traffic_split_test.go b/test/e2e/traffic_split_test.go
index e68e6f7c..42684ee8 100644
--- a/test/e2e/traffic_split_test.go
+++ b/test/e2e/traffic_split_test.go
@@ -148,6 +148,72 @@ func TestTrafficSplit(t *testing.T) {
 		verifyTargets(r, serviceName, expectedTargets, false)
 		test.ServiceDelete(r, serviceName)
 	})
+	t.Run("45:55 automatic traffic split to new @latest and previous revision after mutation", func(t *testing.T) {
+		t.Log("direct 45% traffic explicitly to newly created revision (@latest) and remaining 55 will automatically be directed to previous revision")
+		r := test.NewKnRunResultCollector(t, it)
+		defer r.DumpIfFailed()
+
+		serviceName := test.GetNextServiceName(serviceBase)
+
+		test.ServiceCreate(r, serviceName)
+
+		test.ServiceUpdate(r, serviceName, "--env", "TARGET=v1", "--traffic", "@latest=45")
+
+		rev1 := fmt.Sprintf("%s-00001", serviceName)
+		rev2 := fmt.Sprintf("%s-00002", serviceName)
+
+		expectedTargets := []TargetFields{newTargetFields("", rev2, 45, true), newTargetFields("", rev1, 55, false)}
+		verifyTargets(r, serviceName, expectedTargets, false)
+		test.ServiceDelete(r, serviceName)
+	})
+	t.Run("45:55 automatic traffic split to @latest after mutation", func(t *testing.T) {
+		t.Log("direct 45% traffic explicitly to previous revision and remaining 55 will automatically be directed to @latest")
+		r := test.NewKnRunResultCollector(t, it)
+		defer r.DumpIfFailed()
+
+		serviceName := test.GetNextServiceName(serviceBase)
+
+		test.ServiceCreate(r, serviceName)
+
+		rev1 := fmt.Sprintf("%s-00001", serviceName)
+		rev2 := fmt.Sprintf("%s-00002", serviceName)
+		test.ServiceUpdate(r, serviceName, "--env", "TARGET=v1", "--traffic", fmt.Sprintf("%s=%d", rev1, 45))
+
+		expectedTargets := []TargetFields{newTargetFields("", rev2, 55, true), newTargetFields("", rev1, 45, false)}
+		verifyTargets(r, serviceName, expectedTargets, false)
+		test.ServiceDelete(r, serviceName)
+	})
+	t.Run("automatic traffic split failure", func(t *testing.T) {
+		t.Log("direct 50% traffic to one of the three revisions. Remaining will not be automatically redirected as only one revision should be missing from spec")
+		r := test.NewKnRunResultCollector(t, it)
+		defer r.DumpIfFailed()
+
+		serviceName := test.GetNextServiceName(serviceBase)
+
+		rev1 := fmt.Sprintf("%s-00001", serviceName)
+
+		test.ServiceCreate(r, serviceName)
+
+		test.ServiceUpdate(r, serviceName, "--env", "TARGET=v1")
+		test.ServiceUpdate(r, serviceName, "--env", "TARGET=v2")
+		test.ServiceUpdateWithError(r, serviceName, "--traffic", fmt.Sprintf("%s=%d", rev1, 50))
+
+		test.ServiceDelete(r, serviceName)
+	})
+	t.Run("automatic traffic split failure with @latest", func(t *testing.T) {
+		t.Log("direct 50% traffic to @latest of the three revisions. Remaining will not be automatically redirected as only one revision should be missing from spec")
+		r := test.NewKnRunResultCollector(t, it)
+		defer r.DumpIfFailed()
+
+		serviceName := test.GetNextServiceName(serviceBase)
+
+		test.ServiceCreate(r, serviceName)
+
+		test.ServiceUpdate(r, serviceName, "--env", "TARGET=v1")
+		test.ServiceUpdateWithError(r, serviceName, "--env", "TARGET=v2", "--traffic", "@latest=50")
+
+		test.ServiceDelete(r, serviceName)
+	})
 	t.Run("TagCandidate",
 		func(t *testing.T) {
 			t.Log("tag a revision as candidate, without otherwise changing any traffic split")
@@ -364,6 +430,44 @@ func TestTrafficSplit(t *testing.T) {
 			test.ServiceDelete(r, serviceName)
 		},
 	)
+	t.Run("TagLatestAsCurrentWithoutKey",
+		func(t *testing.T) {
+			t.Log("tag latest ready revision of service as current")
+			r := test.NewKnRunResultCollector(t, it)
+			defer r.DumpIfFailed()
+
+			serviceName := test.GetNextServiceName(serviceBase)
+			// existing state: latest revision has no tag
+			rev1 := fmt.Sprintf("%s-rev-1", serviceName)
+			serviceCreateWithOptions(r, serviceName, "--revision-name", rev1)
+
+			// desired state: tag latest ready revision as 'current'
+			test.ServiceUpdate(r, serviceName, "--tag", "current")
+
+			expectedTargets := []TargetFields{newTargetFields("current", rev1, 100, true)}
+			verifyTargets(r, serviceName, expectedTargets, false)
+			test.ServiceDelete(r, serviceName)
+		},
+	)
+	t.Run("TagMisspelledLatestAsCurrent",
+		func(t *testing.T) {
+			t.Log("tag misspelled @latest tag of service")
+			r := test.NewKnRunResultCollector(t, it)
+			defer r.DumpIfFailed()
+
+			serviceName := test.GetNextServiceName(serviceBase)
+			// existing state: latest revision has no tag
+			rev1 := fmt.Sprintf("%s-rev-1", serviceName)
+			serviceCreateWithOptions(r, serviceName, "--revision-name", rev1)
+
+			// desired state: tag latest ready revision as 'current'
+			test.ServiceUpdateWithError(r, serviceName, "--tag", "@ltest=current")
+
+			expectedTargets := []TargetFields{newTargetFields("", rev1, 100, true)}
+			verifyTargets(r, serviceName, expectedTargets, true)
+			test.ServiceDelete(r, serviceName)
+		},
+	)
 	t.Run("UpdateTag:100:0",
 		func(t *testing.T) {
 			t.Log("update tag for a revision as testing and assign all the traffic to it")
@@ -426,6 +530,24 @@ func TestTrafficSplit(t *testing.T) {
 			test.ServiceDelete(r, serviceName)
 		},
 	)
+	t.Run("CreateWithTag",
+		func(t *testing.T) {
+			t.Log("use --tag with create to create a tagged revision")
+			r := test.NewKnRunResultCollector(t, it)
+			defer r.DumpIfFailed()
+
+			serviceName := test.GetNextServiceName(serviceBase)
+			rev1 := fmt.Sprintf("%s-rev-1", serviceName)
+			serviceCreateWithOptions(r, serviceName, "--tag", "foo", "--revision-name", rev1)
+
+			expectedTargets := []TargetFields{
+				newTargetFields("foo", rev1, 100, true),
+			}
+
+			verifyTargets(r, serviceName, expectedTargets, true)
+			test.ServiceDelete(r, serviceName)
+		},
+	)
 	t.Run("UntagNonExistentTag",
 		func(t *testing.T) {
 			t.Log("use --untag on a tag that does not exist")