Repository: knative/client
Pull request #739 (2020-03-13 02:15:58)

e2e for service export
## Description
Add e2e test for kn service export
<!-- 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 -->

* Add e2e test for 'kn service export'
* Refactor unit test for 'kn service export' 
* Drop the traffic information if only one revision is present in the traffic

<!--
Please add an entrty to CHANGELOG.adoc file, too, as part of your Pull Request.

In the following cases, add a short description of PR to the unreleased section in CHANGELOG.adoc:

- 🎁 New feature
- 🐛 Bug fix
- ✨ Feature Update
- 🐣 Refactoring
- 🗑️ Remove feature or internal logic

See other entries in CHANGELOG.adoc as an example for how to add the entry, including a reference to the corresponding issue/PR

PLEASE DON'T ADD THAT LINE HERE IN THE PULL-REQUEST DESCRIPTION BUT DIRECTLY IN CHANGELOG.ADOC AND ADD CHANGELOG.ADOC AS PART OF YOUR PULL-REQUEST.
-->

<!--
To automatically lint go code in this pull request uncomment the line belpow. 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/739#" title="Author self-approved">itsmurugappan</a>*
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please assign **sixolet**
You can assign the PR to them by writing `/assign @sixolet` 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/master/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":["sixolet"]} -->
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/export.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/739/pull-knative-client-go-coverage/1238287751518883840/artifacts/line-cov.html#file0) | 82.1% | 82.3% | 0.2

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-knative-client-unit-tests | 43a4a3ae173aebcc915530a49ab48bb572eaaf70 | [link](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_client/739/pull-knative-client-unit-tests/1238287751518883844) | `/test pull-knative-client-unit-tests`

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

<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: @itsmurugappan: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-knative-client-unit-tests | 43a4a3ae173aebcc915530a49ab48bb572eaaf70 | [link](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_client/739/pull-knative-client-unit-tests/1238287751518883844) | `/test pull-knative-client-unit-tests`
pull-knative-client-build-tests | 43a4a3ae173aebcc915530a49ab48bb572eaaf70 | [link](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_client/739/pull-knative-client-build-tests/1238287751518883841) | `/test pull-knative-client-build-tests`

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

<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-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/export.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/739/pull-knative-client-go-coverage/1238289637844193284/artifacts/line-cov.html#file0) | 82.1% | 82.3% | 0.2

knative-prow-robot: @itsmurugappan: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-knative-client-build-tests | 43a4a3ae173aebcc915530a49ab48bb572eaaf70 | [link](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_client/739/pull-knative-client-build-tests/1238287751518883841) | `/test pull-knative-client-build-tests`
pull-knative-client-unit-tests | b9b0dbc8d636946fb6655c5e37375a0d4e290163 | [link](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_client/739/pull-knative-client-unit-tests/1238289637844193281) | `/test pull-knative-client-unit-tests`

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

<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: @itsmurugappan: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-knative-client-unit-tests | b9b0dbc8d636946fb6655c5e37375a0d4e290163 | [link](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_client/739/pull-knative-client-unit-tests/1238289637844193281) | `/test pull-knative-client-unit-tests`
pull-knative-client-build-tests | b9b0dbc8d636946fb6655c5e37375a0d4e290163 | [link](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_client/739/pull-knative-client-build-tests/1238289637844193280) | `/test pull-knative-client-build-tests`

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

<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-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/export.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/739/pull-knative-client-go-coverage/1238291399233769473/artifacts/line-cov.html#file0) | 82.1% | 82.3% | 0.2

knative-prow-robot: @itsmurugappan: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-knative-client-build-tests | b9b0dbc8d636946fb6655c5e37375a0d4e290163 | [link](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_client/739/pull-knative-client-build-tests/1238289637844193280) | `/test pull-knative-client-build-tests`
pull-knative-client-unit-tests | 5bebbe72dcd40cb1ef1a04a746f719a1638d07c9 | [link](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_client/739/pull-knative-client-unit-tests/1238291399233769472) | `/test pull-knative-client-unit-tests`

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

<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: @itsmurugappan: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-knative-client-unit-tests | 5bebbe72dcd40cb1ef1a04a746f719a1638d07c9 | [link](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_client/739/pull-knative-client-unit-tests/1238291399233769472) | `/test pull-knative-client-unit-tests`
pull-knative-client-build-tests | 5bebbe72dcd40cb1ef1a04a746f719a1638d07c9 | [link](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_client/739/pull-knative-client-build-tests/1238291399242158080) | `/test pull-knative-client-build-tests`

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

<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-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/export.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/739/pull-knative-client-go-coverage/1238295677256077313/artifacts/line-cov.html#file0) | 82.1% | 82.3% | 0.2

knative-prow-robot: @itsmurugappan: The following tests **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-knative-client-unit-tests | 5bebbe72dcd40cb1ef1a04a746f719a1638d07c9 | [link](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_client/739/pull-knative-client-unit-tests/1238291399233769472) | `/test pull-knative-client-unit-tests`
pull-knative-client-build-tests | d7e9ea71764215a19b8bf88d51c079a4d0ed4b41 | [link](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_client/739/pull-knative-client-build-tests/1238295677260271616) | `/test pull-knative-client-build-tests`

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

<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-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/export.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/739/pull-knative-client-go-coverage/1238297566378987520/artifacts/line-cov.html#file0) | 82.1% | 82.3% | 0.2

maximilien: /ok-to-test
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/export.go](https://storage.cloud.google.com/knative-prow/pr-logs/pull/knative_client/739/pull-knative-client-go-coverage/1238583204688957444/artifacts/line-cov.html#file0) | 82.1% | 82.3% | 0.2


Patch:
diff --git a/docs/cmd/kn_service.md b/docs/cmd/kn_service.md
index ca289a08..bd4794f9 100644
--- a/docs/cmd/kn_service.md
+++ b/docs/cmd/kn_service.md
@@ -30,7 +30,7 @@ kn service [flags]
 * [kn service create](kn_service_create.md)	 - Create a service.
 * [kn service delete](kn_service_delete.md)	 - Delete a service.
 * [kn service describe](kn_service_describe.md)	 - Show details of a service
-* [kn service export](kn_service_export.md)	 - export a service
+* [kn service export](kn_service_export.md)	 - Export a service.
 * [kn service list](kn_service_list.md)	 - List available services.
 * [kn service update](kn_service_update.md)	 - Update a service.
 
diff --git a/docs/cmd/kn_service_export.md b/docs/cmd/kn_service_export.md
index 5c2b7266..b106af53 100644
--- a/docs/cmd/kn_service_export.md
+++ b/docs/cmd/kn_service_export.md
@@ -1,10 +1,10 @@
 ## kn service export
 
-export a service
+Export a service.
 
 ### Synopsis
 
-export a service
+Export a service.
 
 ```
 kn service export NAME [flags]
diff --git a/go.mod b/go.mod
index 7941a665..67ff0da3 100644
--- a/go.mod
+++ b/go.mod
@@ -22,7 +22,7 @@ require (
 	knative.dev/eventing v0.13.1
 	knative.dev/pkg v0.0.0-20200304185554-312b1be35ceb
 	knative.dev/serving v0.13.0
-	knative.dev/test-infra v0.0.0-20200229011351-4dac123b9a3d
+	knative.dev/test-infra v0.0.0-20200317044931-e97f2ecc90ce
 	sigs.k8s.io/yaml v1.1.0
 )
 
diff --git a/go.sum b/go.sum
index 8354f028..55fcbcab 100644
--- a/go.sum
+++ b/go.sum
@@ -598,8 +598,8 @@ knative.dev/pkg v0.0.0-20200304185554-312b1be35ceb h1:cgpFaVF0jb7z+zJGzq30HMfxMm
 knative.dev/pkg v0.0.0-20200304185554-312b1be35ceb/go.mod h1:pgODObA1dTyhNoFxPZTTjNWfx6F0aKsKzn+vaT9XO/Q=
 knative.dev/serving v0.13.0 h1:HkkTVBi6EWoFJcgjXgAVUFdKdxZRulb38dnfnkBYCrQ=
 knative.dev/serving v0.13.0/go.mod h1:x2n255JS2XBI39tmjZ8CwTxIf9EKNMCrkVuiOttLRm0=
-knative.dev/test-infra v0.0.0-20200229011351-4dac123b9a3d h1:YlscBzPOL3Rfyl8844/wHhJNL5uiHDdyaRn6IEVvv64=
-knative.dev/test-infra v0.0.0-20200229011351-4dac123b9a3d/go.mod h1:xcdUkMJrLlBswIZqL5zCuBFOC22WIPMQoVX1L35i0vQ=
+knative.dev/test-infra v0.0.0-20200317044931-e97f2ecc90ce h1:XTqgZ7XLDcRcmGxBwjnEkmQDHT6xg25skjGe6K1H0Cs=
+knative.dev/test-infra v0.0.0-20200317044931-e97f2ecc90ce/go.mod h1:xcdUkMJrLlBswIZqL5zCuBFOC22WIPMQoVX1L35i0vQ=
 modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw=
 modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk=
 modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=
diff --git a/pkg/kn/commands/service/export.go b/pkg/kn/commands/service/export.go
index 1b34abb9..482b47c4 100644
--- a/pkg/kn/commands/service/export.go
+++ b/pkg/kn/commands/service/export.go
@@ -40,7 +40,7 @@ func NewServiceExportCommand(p *commands.KnParams) *cobra.Command {
 
 	command := &cobra.Command{
 		Use:   "export NAME",
-		Short: "export a service",
+		Short: "Export a service.",
 		Example: `
   # Export a service in yaml format
   kn service export foo -n bar -o yaml
@@ -125,7 +125,7 @@ func constructServicefromRevision(latestSvc *servingv1.Service, revision serving
 		TypeMeta: latestSvc.TypeMeta,
 	}
 
-	exportedSvc.Spec.Template = servingv1.RevisionTemplateSpec{
+	exportedSvc.Spec.ConfigurationSpec.Template = servingv1.RevisionTemplateSpec{
 		Spec:       revision.Spec,
 		ObjectMeta: latestSvc.Spec.ConfigurationSpec.Template.ObjectMeta,
 	}
@@ -164,8 +164,10 @@ func exportServiceWithActiveRevisions(latestSvc *servingv1.Service, client clien
 		return nil, fmt.Errorf("no revisions found for service %s", latestSvc.ObjectMeta.Name)
 	}
 
-	//set traffic in the latest revision
-	exportedSvcItems[len(exportedSvcItems)-1] = setTrafficSplit(latestSvc, exportedSvcItems[len(exportedSvcItems)-1])
+	//set traffic in the latest revision on if there is traffic split
+	if len(latestSvc.Spec.RouteSpec.Traffic) > 1 {
+		exportedSvcItems[len(exportedSvcItems)-1] = setTrafficSplit(latestSvc, exportedSvcItems[len(exportedSvcItems)-1])
+	}
 
 	typeMeta := metav1.TypeMeta{
 		APIVersion: "v1",
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 79ab3380..429483e4 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -525,7 +525,7 @@ knative.dev/serving/pkg/autoscaler/config
 knative.dev/serving/pkg/client/clientset/versioned/scheme
 knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1
 knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1/fake
-# knative.dev/test-infra v0.0.0-20200229011351-4dac123b9a3d
+# knative.dev/test-infra v0.0.0-20200317044931-e97f2ecc90ce
 knative.dev/test-infra/scripts
 # sigs.k8s.io/kustomize v2.0.3+incompatible
 sigs.k8s.io/kustomize/pkg/commands/build


Test patch:
diff --git a/pkg/kn/commands/service/export_test.go b/pkg/kn/commands/service/export_test.go
index 59662281..8bac812d 100644
--- a/pkg/kn/commands/service/export_test.go
+++ b/pkg/kn/commands/service/export_test.go
@@ -17,6 +17,7 @@ package service
 import (
 	"encoding/json"
 	"fmt"
+	"strconv"
 	"testing"
 
 	"gotest.tools/assert"
@@ -32,188 +33,97 @@ import (
 	"sigs.k8s.io/yaml"
 )
 
-func TestServiceExport(t *testing.T) {
-	var svcs []*servingv1.Service
-	typeMeta := metav1.TypeMeta{
-		Kind:       "service",
-		APIVersion: "serving.knative.dev/v1",
-	}
+type expectedServiceOption func(*servingv1.Service)
+type expectedRevisionOption func(*servingv1.Revision)
 
-	// case 1 - plain svc
-	plainService := getService("foo")
-	svcs = append(svcs, plainService)
-
-	// case 2 - svc with env variables
-	envSvc := getService("foo")
-	envVars := []v1.EnvVar{
-		{Name: "a", Value: "mouse"},
-		{Name: "b", Value: "cookie"},
-		{Name: "empty", Value: ""},
-	}
-	template := &envSvc.Spec.Template
-	template.Spec.Containers[0].Env = envVars
-	template.Spec.Containers[0].Image = "gcr.io/foo/bar:baz"
-	template.Annotations = map[string]string{servinglib.UserImageAnnotationKey: "gcr.io/foo/bar:baz"}
-	svcs = append(svcs, envSvc)
-
-	//case 3 - svc with labels
-	labelService := getService("foo")
-	expected := map[string]string{
-		"a":     "mouse",
-		"b":     "cookie",
-		"empty": "",
-	}
-	labelService.Labels = expected
-	labelService.Spec.Template.Annotations = map[string]string{
-		servinglib.UserImageAnnotationKey: "gcr.io/foo/bar:baz",
-	}
-	template = &labelService.Spec.Template
-	template.ObjectMeta.Labels = expected
-	template.Spec.Containers[0].Image = "gcr.io/foo/bar:baz"
-	svcs = append(svcs, labelService)
-
-	//case 4 - config map
-	CMservice := getService("foo")
-	template = &CMservice.Spec.Template
-	template.Spec.Containers[0].EnvFrom = []v1.EnvFromSource{
-		{
-			ConfigMapRef: &v1.ConfigMapEnvSource{
-				LocalObjectReference: v1.LocalObjectReference{
-					Name: "config-map-name",
-				},
-			},
-		},
-	}
-	template.Spec.Containers[0].Image = "gcr.io/foo/bar:baz"
-	template.Annotations = map[string]string{servinglib.UserImageAnnotationKey: "gcr.io/foo/bar:baz"}
-	svcs = append(svcs, CMservice)
-
-	//case 5 - volume mount and secrets
-	Volservice := getService("foo")
-	template = &Volservice.Spec.Template
-	template.Spec.Volumes = []v1.Volume{
-		{
-			Name: "volume-name",
-			VolumeSource: v1.VolumeSource{
-				Secret: &v1.SecretVolumeSource{
-					SecretName: "secret-name",
-				},
-			},
-		},
-	}
+func TestServiceExport(t *testing.T) {
 
-	template.Spec.Containers[0].VolumeMounts = []v1.VolumeMount{
-		{
-			Name:      "volume-name",
-			MountPath: "/mount/path",
-			ReadOnly:  true,
-		},
+	svcs := []*servingv1.Service{
+		getServiceWithOptions(getService("foo"), withContainer()),
+		getServiceWithOptions(getService("foo"), withContainer(), withEnv([]v1.EnvVar{{Name: "a", Value: "mouse"}})),
+		getServiceWithOptions(getService("foo"), withContainer(), withLabels(map[string]string{"a": "mouse", "b": "cookie", "empty": ""})),
+		getServiceWithOptions(getService("foo"), withContainer(), withEnvFrom([]string{"cm-name"})),
+		getServiceWithOptions(getService("foo"), withContainer(), withVolumeandSecrets("volName", "secretName")),
 	}
-	svcs = append(svcs, Volservice)
-
-	template.Spec.Containers[0].Image = "gcr.io/foo/bar:baz"
-	template.Annotations = map[string]string{servinglib.UserImageAnnotationKey: "gcr.io/foo/bar:baz"}
 
 	for _, svc := range svcs {
-		svc.TypeMeta = typeMeta
 		callServiceExportTest(t, svc)
 	}
-
 }
 
 func callServiceExportTest(t *testing.T, expectedService *servingv1.Service) {
 	// New mock client
 	client := knclient.NewMockKnServiceClient(t)
-
 	// Recording:
 	r := client.Recorder()
-
 	r.GetService(expectedService.ObjectMeta.Name, expectedService, nil)
 
 	output, err := executeServiceCommand(client, "export", expectedService.ObjectMeta.Name, "-o", "yaml")
-
 	assert.NilError(t, err)
 
-	expectedService.ObjectMeta.Namespace = ""
-
-	expSvcYaml, err := yaml.Marshal(expectedService)
-
+	actSvc := servingv1.Service{}
+	err = yaml.Unmarshal([]byte(output), &actSvc)
 	assert.NilError(t, err)
-
-	assert.Equal(t, string(expSvcYaml), output)
-
+	stripExpectedSvcVariables(expectedService)
+	assert.DeepEqual(t, expectedService, &actSvc)
 	// Validate that all recorded API methods have been called
 	r.Validate()
 }
 
 func TestServiceExportwithMultipleRevisions(t *testing.T) {
-	//case 1 = 2 revisions with traffic split
-	trafficSplitService := createServiceTwoRevsionsWithTraffic("foo", true)
-
-	multiRevs := createTestRevisionList("rev", "foo")
+	//case 1 - 2 revisions with traffic split
+	expSvc1 := getServiceWithOptions(getService("foo"), withContainer(), withServiceRevisionName("foo-rev-1"))
+	stripExpectedSvcVariables(expSvc1)
+	expSvc2 := getServiceWithOptions(getService("foo"), withContainer(), withTrafficSplit([]string{"foo-rev-1", "foo-rev-2"}, []int{50, 50}, []string{"latest", "current"}), withServiceRevisionName("foo-rev-2"))
+	stripExpectedSvcVariables(expSvc2)
+	latestSvc := getServiceWithOptions(getService("foo"), withContainer(), withTrafficSplit([]string{"foo-rev-1", "foo-rev-2"}, []int{50, 50}, []string{"latest", "current"}))
+
+	expSvcList := servingv1.ServiceList{
+		TypeMeta: metav1.TypeMeta{
+			APIVersion: "v1",
+			Kind:       "List",
+		},
+		Items: []servingv1.Service{*expSvc1, *expSvc2},
+	}
 
-	callServiceExportHistoryTest(t, trafficSplitService, multiRevs)
+	multiRevs := getRevisionList("rev", "foo")
 
-	//case 2 - same revisions no traffic split
-	noTrafficSplitService := createServiceTwoRevsionsWithTraffic("foo", false)
+	callServiceExportHistoryTest(t, latestSvc, multiRevs, &expSvcList)
 
-	callServiceExportHistoryTest(t, noTrafficSplitService, multiRevs)
+	// case 2 - same revisions no traffic split
+	expSvc2 = getServiceWithOptions(getService("foo"), withContainer(), withServiceRevisionName("foo-rev-2"))
+	stripExpectedSvcVariables(expSvc2)
+	expSvcList = servingv1.ServiceList{
+		TypeMeta: metav1.TypeMeta{
+			APIVersion: "v1",
+			Kind:       "List",
+		},
+		Items: []servingv1.Service{*expSvc2},
+	}
+	latestSvc = getServiceWithOptions(getService("foo"), withContainer(), withTrafficSplit([]string{"foo-rev-2"}, []int{100}, []string{"latest"}))
+	callServiceExportHistoryTest(t, latestSvc, multiRevs, &expSvcList)
 }
 
-func callServiceExportHistoryTest(t *testing.T, expectedService *servingv1.Service, revs *servingv1.RevisionList) {
+func callServiceExportHistoryTest(t *testing.T, latestSvc *servingv1.Service, revs *servingv1.RevisionList, expSvcList *servingv1.ServiceList) {
 	// New mock client
 	client := knclient.NewMockKnServiceClient(t)
-
 	// Recording:
 	r := client.Recorder()
 
-	r.GetService(expectedService.ObjectMeta.Name, expectedService, nil)
-
+	r.GetService(latestSvc.ObjectMeta.Name, latestSvc, nil)
 	r.ListRevisions(mock.Any(), revs, nil)
 
-	output, err := executeServiceCommand(client, "export", expectedService.ObjectMeta.Name, "--with-revisions", "-o", "json")
-
+	output, err := executeServiceCommand(client, "export", latestSvc.ObjectMeta.Name, "--with-revisions", "-o", "json")
 	assert.NilError(t, err)
 
 	actSvcList := servingv1.ServiceList{}
-
-	json.Unmarshal([]byte(output), &actSvcList)
-
-	for i, actSvc := range actSvcList.Items {
-		var checkTraffic bool
-		if i == (len(actSvcList.Items) - 1) {
-			checkTraffic = true
-		}
-		validateServiceWithRevisionHistory(t, expectedService, revs, actSvc, checkTraffic)
-	}
-
+	err = json.Unmarshal([]byte(output), &actSvcList)
+	assert.NilError(t, err)
+	assert.DeepEqual(t, expSvcList, &actSvcList)
 	// Validate that all recorded API methods have been called
 	r.Validate()
 }
 
-func validateServiceWithRevisionHistory(t *testing.T, expectedsvc *servingv1.Service, expectedRevList *servingv1.RevisionList, actualSvc servingv1.Service, checkTraffic bool) {
-	var expectedRev servingv1.Revision
-	var routeSpec servingv1.RouteSpec
-	for _, rev := range expectedRevList.Items {
-		if actualSvc.Spec.ConfigurationSpec.Template.ObjectMeta.Name == rev.ObjectMeta.Name {
-			expectedRev = rev
-			break
-		}
-	}
-	expectedsvc.Spec.ConfigurationSpec.Template.ObjectMeta.Name = expectedRev.ObjectMeta.Name
-	expectedsvc.Spec.Template.Spec = expectedRev.Spec
-
-	stripExpectedSvcVariables(expectedsvc)
-
-	if !checkTraffic {
-		routeSpec = expectedsvc.Spec.RouteSpec
-		expectedsvc.Spec.RouteSpec = servingv1.RouteSpec{}
-	}
-	assert.DeepEqual(t, expectedsvc, &actualSvc)
-
-	expectedsvc.Spec.RouteSpec = routeSpec
-}
-
 func TestServiceExportError(t *testing.T) {
 	// New mock client
 	client := knclient.NewMockKnServiceClient(t)
@@ -225,98 +135,176 @@ func TestServiceExportError(t *testing.T) {
 	assert.Error(t, err, "'kn service export' requires output format")
 }
 
-func createTestRevisionList(revision string, service string) *servingv1.RevisionList {
-	labels1 := make(map[string]string)
-	labels1[apiserving.ConfigurationGenerationLabelKey] = "1"
-	labels1[apiserving.ServiceLabelKey] = service
+func getRevisionList(revision string, service string) *servingv1.RevisionList {
+	rev1 := getRevisionWithOptions(
+		service,
+		withRevisionGeneration("1"),
+		withRevisionName(fmt.Sprintf("%s-%s-%d", service, revision, 1)),
+	)
+
+	rev2 := getRevisionWithOptions(
+		service,
+		withRevisionGeneration("2"),
+		withRevisionName(fmt.Sprintf("%s-%s-%d", service, revision, 2)),
+	)
+
+	return &servingv1.RevisionList{
+		TypeMeta: metav1.TypeMeta{
+			APIVersion: "v1",
+			Kind:       "List",
+		},
+		Items: []servingv1.Revision{rev1, rev2},
+	}
+}
 
-	labels2 := make(map[string]string)
-	labels2[apiserving.ConfigurationGenerationLabelKey] = "2"
-	labels2[apiserving.ServiceLabelKey] = service
+func stripExpectedSvcVariables(expectedsvc *servingv1.Service) {
+	expectedsvc.ObjectMeta.Namespace = ""
+	expectedsvc.Spec.Template.Spec.Containers[0].Resources = v1.ResourceRequirements{}
+	expectedsvc.Status = servingv1.ServiceStatus{}
+	expectedsvc.ObjectMeta.Annotations = nil
+	expectedsvc.ObjectMeta.CreationTimestamp = metav1.Time{}
+}
 
-	rev1 := servingv1.Revision{
+func getRevisionWithOptions(service string, options ...expectedRevisionOption) servingv1.Revision {
+	rev := servingv1.Revision{
 		TypeMeta: metav1.TypeMeta{
 			Kind:       "Revision",
 			APIVersion: "serving.knative.dev/v1",
 		},
 		ObjectMeta: metav1.ObjectMeta{
-			Name:       fmt.Sprintf("%s-%s-%d", service, revision, 1),
-			Namespace:  "default",
-			Generation: int64(1),
-			Labels:     labels1,
+			Namespace: "default",
+			Labels: map[string]string{
+				apiserving.ServiceLabelKey: service,
+			},
 		},
 		Spec: servingv1.RevisionSpec{
 			PodSpec: v1.PodSpec{
 				Containers: []v1.Container{
 					{
-						Image: "gcr.io/test/image:v1",
-						Env: []v1.EnvVar{
-							{Name: "env1", Value: "eval1"},
-							{Name: "env2", Value: "eval2"},
-						},
-						EnvFrom: []v1.EnvFromSource{
-							{ConfigMapRef: &v1.ConfigMapEnvSource{LocalObjectReference: v1.LocalObjectReference{Name: "test1"}}},
-							{ConfigMapRef: &v1.ConfigMapEnvSource{LocalObjectReference: v1.LocalObjectReference{Name: "test2"}}},
-						},
-						Ports: []v1.ContainerPort{
-							{ContainerPort: 8080},
-						},
+						Image: "gcr.io/foo/bar:baz",
 					},
 				},
 			},
 		},
 	}
+	for _, fn := range options {
+		fn(&rev)
+	}
+	return rev
+}
+
+func getServiceWithOptions(svc *servingv1.Service, options ...expectedServiceOption) *servingv1.Service {
+	svc.TypeMeta = metav1.TypeMeta{
+		Kind:       "service",
+		APIVersion: "serving.knative.dev/v1",
+	}
 
-	rev2 := rev1
+	for _, fn := range options {
+		fn(svc)
+	}
+
+	return svc
+}
 
-	rev2.Spec.PodSpec.Containers[0].Image = "gcr.io/test/image:v2"
-	rev2.ObjectMeta.Labels = labels2
-	rev2.ObjectMeta.Generation = int64(2)
-	rev2.ObjectMeta.Name = fmt.Sprintf("%s-%s-%d", service, revision, 2)
+func withLabels(labels map[string]string) expectedServiceOption {
+	return func(svc *servingv1.Service) {
+		svc.Spec.ConfigurationSpec.Template.ObjectMeta.Labels = labels
+	}
+}
 
-	typeMeta := metav1.TypeMeta{
-		APIVersion: "v1",
-		Kind:       "List",
+func withEnvFrom(cmNames []string) expectedServiceOption {
+	return func(svc *servingv1.Service) {
+		var list []v1.EnvFromSource
+		for _, cmName := range cmNames {
+			list = append(list, v1.EnvFromSource{
+				ConfigMapRef: &v1.ConfigMapEnvSource{
+					LocalObjectReference: v1.LocalObjectReference{
+						Name: cmName,
+					},
+				},
+			})
+		}
+		svc.Spec.ConfigurationSpec.Template.Spec.PodSpec.Containers[0].EnvFrom = list
 	}
+}
 
-	return &servingv1.RevisionList{
-		TypeMeta: typeMeta,
-		Items:    []servingv1.Revision{rev1, rev2},
+func withEnv(env []v1.EnvVar) expectedServiceOption {
+	return func(svc *servingv1.Service) {
+		svc.Spec.ConfigurationSpec.Template.Spec.PodSpec.Containers[0].Env = env
 	}
 }
 
-func createServiceTwoRevsionsWithTraffic(svc string, trafficSplit bool) *servingv1.Service {
-	expectedService := createTestService(svc, []string{svc + "-rev-1", svc + "-rev-2"}, goodConditions())
-	expectedService.Status.Traffic[0].LatestRevision = ptr.Bool(true)
-	expectedService.Status.Traffic[0].Tag = "latest"
-	expectedService.Status.Traffic[1].Tag = "current"
+func withContainer() expectedServiceOption {
+	return func(svc *servingv1.Service) {
+		svc.Spec.ConfigurationSpec.Template.Spec.Containers[0].Image = "gcr.io/foo/bar:baz"
+		svc.Spec.ConfigurationSpec.Template.Annotations = map[string]string{servinglib.UserImageAnnotationKey: "gcr.io/foo/bar:baz"}
 
-	if trafficSplit {
-		trafficList := []servingv1.TrafficTarget{
+	}
+}
+
+func withVolumeandSecrets(volName string, secretName string) expectedServiceOption {
+	return func(svc *servingv1.Service) {
+		template := &svc.Spec.Template
+		template.Spec.Volumes = []v1.Volume{
 			{
-				RevisionName: "foo-rev-1",
-				Percent:      ptr.Int64(int64(50)),
-			}, {
-				RevisionName: "foo-rev-2",
-				Percent:      ptr.Int64(int64(50)),
-			}}
-		expectedService.Spec.RouteSpec = servingv1.RouteSpec{Traffic: trafficList}
-	} else {
-		trafficList := []servingv1.TrafficTarget{
+				Name: volName,
+				VolumeSource: v1.VolumeSource{
+					Secret: &v1.SecretVolumeSource{
+						SecretName: secretName,
+					},
+				},
+			},
+		}
+
+		template.Spec.Containers[0].VolumeMounts = []v1.VolumeMount{
 			{
-				RevisionName: "foo-rev-2",
-				Percent:      ptr.Int64(int64(50)),
-			}}
-		expectedService.Spec.RouteSpec = servingv1.RouteSpec{Traffic: trafficList}
+				Name:      volName,
+				MountPath: "/mount/path",
+				ReadOnly:  true,
+			},
+		}
 	}
+}
 
-	return &expectedService
+func withRevisionGeneration(gen string) expectedRevisionOption {
+	return func(rev *servingv1.Revision) {
+		i, _ := strconv.Atoi(gen)
+		rev.ObjectMeta.Generation = int64(i)
+		rev.ObjectMeta.Labels[apiserving.ConfigurationGenerationLabelKey] = gen
+	}
 }
 
-func stripExpectedSvcVariables(expectedsvc *servingv1.Service) {
-	expectedsvc.ObjectMeta.Namespace = ""
-	expectedsvc.Spec.Template.Spec.Containers[0].Resources = v1.ResourceRequirements{}
-	expectedsvc.Status = servingv1.ServiceStatus{}
-	expectedsvc.ObjectMeta.Annotations = nil
-	expectedsvc.ObjectMeta.CreationTimestamp = metav1.Time{}
+func withRevisionName(name string) expectedRevisionOption {
+	return func(rev *servingv1.Revision) {
+		rev.ObjectMeta.Name = name
+	}
+}
+
+func withServiceRevisionName(name string) expectedServiceOption {
+	return func(svc *servingv1.Service) {
+		svc.Spec.ConfigurationSpec.Template.ObjectMeta.Name = name
+	}
+}
+
+func withTrafficSplit(revisions []string, percentages []int, tags []string) expectedServiceOption {
+	return func(svc *servingv1.Service) {
+		var trafficTargets []servingv1.TrafficTarget
+		for i, rev := range revisions {
+			trafficTargets = append(trafficTargets, servingv1.TrafficTarget{
+				Percent: ptr.Int64(int64(percentages[i])),
+			})
+			if tags[i] != "" {
+				trafficTargets[i].Tag = tags[i]
+			}
+			if rev == "latest" {
+				trafficTargets[i].LatestRevision = ptr.Bool(true)
+			} else {
+				trafficTargets[i].RevisionName = rev
+				trafficTargets[i].LatestRevision = ptr.Bool(false)
+			}
+		}
+		svc.Spec.RouteSpec = servingv1.RouteSpec{
+			Traffic: trafficTargets,
+		}
+	}
 }
diff --git a/test/e2e/service_export_import_apply_test.go b/test/e2e/service_export_import_apply_test.go
new file mode 100644
index 00000000..24564ee4
--- /dev/null
+++ b/test/e2e/service_export_import_apply_test.go
@@ -0,0 +1,264 @@
+// 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.
+
+// +build e2e
+// +build !eventing
+
+package e2e
+
+import (
+	"encoding/json"
+	"testing"
+
+	"gotest.tools/assert"
+
+	corev1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/util/intstr"
+	"knative.dev/pkg/ptr"
+	"sigs.k8s.io/yaml"
+
+	servingv1 "knative.dev/serving/pkg/apis/serving/v1"
+)
+
+type expectedServiceOption func(*servingv1.Service)
+
+func TestServiceExportImportApply(t *testing.T) {
+	t.Parallel()
+	test, err := NewE2eTest()
+	assert.NilError(t, err)
+	defer func() {
+		assert.NilError(t, test.Teardown())
+	}()
+
+	r := NewKnRunResultCollector(t)
+	defer r.DumpIfFailed()
+
+	t.Log("create service with byo revision")
+	test.serviceCreateWithOptions(t, r, "hello", "--revision-name", "rev1")
+
+	t.Log("export service and compare")
+	test.serviceExport(t, r, "hello", getSvc(withName("hello"), withRevisionName("hello-rev1"), withAnnotations()), "-o", "json")
+
+	t.Log("update service - add env variable")
+	test.serviceUpdateWithOptions(t, r, "hello", "--env", "key1=val1", "--revision-name", "rev2", "--no-lock-to-digest")
+	test.serviceExport(t, r, "hello", getSvc(withName("hello"), withRevisionName("hello-rev2"), withEnv("key1", "val1")), "-o", "json")
+	test.serviceExportWithRevisions(t, r, "hello", getSvcListWithOneRevision(), "--with-revisions", "-o", "yaml")
+
+	t.Log("update service with tag and split traffic")
+	test.serviceUpdateWithOptions(t, r, "hello", "--tag", "hello-rev1=candidate", "--traffic", "candidate=2%,@latest=98%")
+	test.serviceExportWithRevisions(t, r, "hello", getSvcListWithTags(), "--with-revisions", "-o", "yaml")
+
+	t.Log("update service - untag, add env variable and traffic split")
+	test.serviceUpdateWithOptions(t, r, "hello", "--untag", "candidate")
+	test.serviceUpdateWithOptions(t, r, "hello", "--env", "key2=val2", "--revision-name", "rev3", "--traffic", "hello-rev1=30,hello-rev2=30,hello-rev3=40")
+	test.serviceExportWithRevisions(t, r, "hello", getSvcListWOTags(), "--with-revisions", "-o", "yaml")
+}
+
+func (test *e2eTest) serviceExport(t *testing.T, r *KnRunResultCollector, serviceName string, expService servingv1.Service, options ...string) {
+	command := []string{"service", "export", serviceName}
+	command = append(command, options...)
+	out := test.kn.Run(command...)
+	validateExportedService(t, out.Stdout, expService)
+	r.AssertNoError(out)
+}
+
+func validateExportedService(t *testing.T, out string, expService servingv1.Service) {
+	actSvcJSON := servingv1.Service{}
+	err := json.Unmarshal([]byte(out), &actSvcJSON)
+	assert.NilError(t, err)
+	assert.DeepEqual(t, &expService, &actSvcJSON)
+}
+
+func (test *e2eTest) serviceExportWithRevisions(t *testing.T, r *KnRunResultCollector, serviceName string, expServiceList servingv1.ServiceList, options ...string) {
+	command := []string{"service", "export", serviceName}
+	command = append(command, options...)
+	out := test.kn.Run(command...)
+	validateExportedServiceList(t, out.Stdout, expServiceList)
+	r.AssertNoError(out)
+}
+
+func validateExportedServiceList(t *testing.T, out string, expServiceList servingv1.ServiceList) {
+	actYaml := servingv1.ServiceList{}
+	err := yaml.Unmarshal([]byte(out), &actYaml)
+	assert.NilError(t, err)
+	assert.DeepEqual(t, &expServiceList, &actYaml)
+}
+
+func getSvc(options ...expectedServiceOption) servingv1.Service {
+	svc := servingv1.Service{
+		Spec: servingv1.ServiceSpec{
+			ConfigurationSpec: servingv1.ConfigurationSpec{
+				Template: servingv1.RevisionTemplateSpec{
+					Spec: servingv1.RevisionSpec{
+						ContainerConcurrency: ptr.Int64(int64(0)),
+						TimeoutSeconds:       ptr.Int64(int64(300)),
+						PodSpec: corev1.PodSpec{
+							Containers: []corev1.Container{
+								{
+									Name:      "user-container",
+									Image:     KnDefaultTestImage,
+									Resources: corev1.ResourceRequirements{},
+									ReadinessProbe: &corev1.Probe{
+										SuccessThreshold: int32(1),
+										Handler: corev1.Handler{
+											TCPSocket: &corev1.TCPSocketAction{
+												Port: intstr.FromInt(0),
+											},
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+		TypeMeta: metav1.TypeMeta{
+			Kind:       "Service",
+			APIVersion: "serving.knative.dev/v1",
+		},
+		ObjectMeta: metav1.ObjectMeta{
+			Name: "",
+		},
+	}
+	for _, fn := range options {
+		fn(&svc)
+	}
+	return svc
+}
+
+func getSvcListWOTags() servingv1.ServiceList {
+	return servingv1.ServiceList{
+		TypeMeta: metav1.TypeMeta{
+			APIVersion: "v1",
+			Kind:       "List",
+		},
+		Items: []servingv1.Service{
+			getSvc(
+				withName("hello"),
+				withRevisionName("hello-rev1"),
+			),
+			getSvc(
+				withName("hello"),
+				withRevisionName("hello-rev2"),
+				withEnv("key1", "val1"),
+			),
+			getSvc(
+				withName("hello"),
+				withRevisionName("hello-rev3"),
+				withEnv("key1", "val1"), withEnv("key2", "val2"),
+				withTrafficSplit([]string{"hello-rev1", "hello-rev2", "hello-rev3"}, []int{30, 30, 40}, []string{"", "", ""}),
+			),
+		},
+	}
+}
+
+func getSvcListWithTags() servingv1.ServiceList {
+	return servingv1.ServiceList{
+		TypeMeta: metav1.TypeMeta{
+			APIVersion: "v1",
+			Kind:       "List",
+		},
+		Items: []servingv1.Service{
+			getSvc(
+				withName("hello"),
+				withRevisionName("hello-rev1"),
+			),
+			getSvc(
+				withName("hello"),
+				withRevisionName("hello-rev2"),
+				withEnv("key1", "val1"),
+				withTrafficSplit([]string{"latest", "hello-rev1"}, []int{98, 2}, []string{"", "candidate"}),
+			),
+		},
+	}
+}
+
+func getSvcListWithOneRevision() servingv1.ServiceList {
+	return servingv1.ServiceList{
+		TypeMeta: metav1.TypeMeta{
+			APIVersion: "v1",
+			Kind:       "List",
+		},
+		Items: []servingv1.Service{
+			getSvc(
+				withName("hello"),
+				withRevisionName("hello-rev2"),
+				withEnv("key1", "val1"),
+			),
+		},
+	}
+}
+
+func withRevisionName(revName string) expectedServiceOption {
+	return func(svc *servingv1.Service) {
+		svc.Spec.ConfigurationSpec.Template.ObjectMeta.Name = revName
+	}
+}
+
+func withAnnotations() expectedServiceOption {
+	return func(svc *servingv1.Service) {
+		svc.Spec.ConfigurationSpec.Template.ObjectMeta.Annotations = map[string]string{
+			"client.knative.dev/user-image": "gcr.io/knative-samples/helloworld-go",
+		}
+	}
+}
+
+func withName(name string) expectedServiceOption {
+	return func(svc *servingv1.Service) {
+		svc.ObjectMeta.Name = name
+	}
+}
+
+func withEnv(key string, val string) expectedServiceOption {
+	return func(svc *servingv1.Service) {
+		env := []corev1.EnvVar{
+			{
+				Name:  key,
+				Value: val,
+			},
+		}
+		currentEnv := svc.Spec.ConfigurationSpec.Template.Spec.PodSpec.Containers[0].Env
+		if len(currentEnv) > 0 {
+			svc.Spec.ConfigurationSpec.Template.Spec.PodSpec.Containers[0].Env = append(currentEnv, env...)
+		} else {
+			svc.Spec.ConfigurationSpec.Template.Spec.PodSpec.Containers[0].Env = env
+		}
+
+	}
+}
+
+func withTrafficSplit(revisions []string, percentages []int, tags []string) expectedServiceOption {
+	return func(svc *servingv1.Service) {
+		var trafficTargets []servingv1.TrafficTarget
+		for i, rev := range revisions {
+			trafficTargets = append(trafficTargets, servingv1.TrafficTarget{
+				Percent: ptr.Int64(int64(percentages[i])),
+			})
+			if tags[i] != "" {
+				trafficTargets[i].Tag = tags[i]
+			}
+			if rev == "latest" {
+				trafficTargets[i].LatestRevision = ptr.Bool(true)
+			} else {
+				trafficTargets[i].RevisionName = rev
+				trafficTargets[i].LatestRevision = ptr.Bool(false)
+			}
+		}
+		svc.Spec.RouteSpec = servingv1.RouteSpec{
+			Traffic: trafficTargets,
+		}
+	}
+}
diff --git a/vendor/knative.dev/test-infra/scripts/markdown-link-check-config.rc b/vendor/knative.dev/test-infra/scripts/markdown-link-check-config.rc
index 9d802a0d..49b042e8 100644
--- a/vendor/knative.dev/test-infra/scripts/markdown-link-check-config.rc
+++ b/vendor/knative.dev/test-infra/scripts/markdown-link-check-config.rc
@@ -1,5 +1,5 @@
 # For help, see
 # https://github.com/raviqqe/liche/blob/master/README.md
 
-# Don't check localhost links
--x "^https?://localhost($|[:/].*)"
+# Don't check localhost links and don't check templated links
+-x "(^https?://localhost($|[:/].*))|(^https://.*{{.*$)"
diff --git a/vendor/knative.dev/test-infra/scripts/presubmit-tests.sh b/vendor/knative.dev/test-infra/scripts/presubmit-tests.sh
index c14f2517..a7f95657 100644
--- a/vendor/knative.dev/test-infra/scripts/presubmit-tests.sh
+++ b/vendor/knative.dev/test-infra/scripts/presubmit-tests.sh
@@ -147,14 +147,20 @@ function markdown_build_tests() {
 
 # Default build test runner that:
 # * check markdown files
-# * `go build` on the entire repo
 # * run `/hack/verify-codegen.sh` (if it exists)
+# * `go build` on the entire repo
 # * check licenses in all go packages
 function default_build_test_runner() {
   local failed=0
-  # Perform markdown build checks first
+  # Perform markdown build checks
   markdown_build_tests || failed=1
-  # For documentation PRs, just check the md files
+  # Run verify-codegen check
+  if [[ -f ./hack/verify-codegen.sh ]]; then
+    subheader "Checking autogenerated code is up-to-date"
+    report_build_test Verify_CodeGen ./hack/verify-codegen.sh || failed=1
+  fi
+  # For documentation PRs, just check the md files and run
+  # verify-codegen (as md files can be auto-generated in some repos).
   (( IS_DOCUMENTATION_PR )) && return ${failed}
   # Don't merge these two lines, or return code will always be 0.
   local go_pkg_dirs
@@ -186,13 +192,9 @@ function default_build_test_runner() {
     # Remove unused generated binary, if any.
     rm -f e2e.test
   done
-  
+
   local errors_go="$(echo -e "${errors_go1}\n${errors_go2}" | uniq)"
   create_junit_xml _build_tests Build_Go "${errors_go}"
-  if [[ -f ./hack/verify-codegen.sh ]]; then
-    subheader "Checking autogenerated code is up-to-date"
-    report_build_test Verify_CodeGen ./hack/verify-codegen.sh || failed=1
-  fi
   # Check that we don't have any forbidden licenses in our images.
   subheader "Checking for forbidden licenses"
   report_build_test Check_Licenses check_licenses ${go_pkg_dirs} || failed=1
diff --git a/vendor/knative.dev/test-infra/scripts/release.sh b/vendor/knative.dev/test-infra/scripts/release.sh
index 915fc97f..d23c4c33 100644
--- a/vendor/knative.dev/test-infra/scripts/release.sh
+++ b/vendor/knative.dev/test-infra/scripts/release.sh
@@ -498,9 +498,30 @@ function publish_artifacts() {
 
 # Entry point for a release script.
 function main() {
+  parse_flags "$@"
+
+  # Checkout specific branch, if necessary
+  local current_branch
+  current_branch="$(git rev-parse --abbrev-ref HEAD)"
+  if [[ -n "${RELEASE_BRANCH}" && -z "${FROM_NIGHTLY_RELEASE}" && "${current_branch}" != "${RELEASE_BRANCH}" ]]; then
+    setup_upstream
+    setup_branch
+    # When it runs in Prow, the origin is identical with upstream, and previous
+    # fetch already fetched release-* branches, so no need to `checkout -b`
+    if (( IS_PROW )); then
+      git checkout "${RELEASE_BRANCH}" || abort "cannot checkout branch ${RELEASE_BRANCH}"
+    else
+      git checkout -b "${RELEASE_BRANCH}" upstream/"${RELEASE_BRANCH}" || abort "cannot checkout branch ${RELEASE_BRANCH}"
+    fi
+    # HACK HACK HACK
+    # Rerun the release script from the release branch. Fixes https://github.com/knative/test-infra/issues/1262
+    ./hack/release.sh "$@"
+    exit "$?"
+  fi
+
   function_exists build_release || abort "function 'build_release()' not defined"
   [[ -x ${VALIDATION_TESTS} ]] || abort "test script '${VALIDATION_TESTS}' doesn't exist"
-  parse_flags "$@"
+
   # Log what will be done and where.
   banner "Release configuration"
   if which gcloud &>/dev/null ; then
@@ -533,13 +554,6 @@ function main() {
   fi
   [[ -n "${RELEASE_NOTES}" ]] && echo "- Release notes are generated from '${RELEASE_NOTES}'"
 
-  # Checkout specific branch, if necessary
-  if [[ -n "${RELEASE_BRANCH}" && -z "${FROM_NIGHTLY_RELEASE}" ]]; then
-    setup_upstream
-    setup_branch
-    git checkout upstream/${RELEASE_BRANCH} || abort "cannot checkout branch ${RELEASE_BRANCH}"
-  fi
-
   if [[ -n "${FROM_NIGHTLY_RELEASE}" ]]; then
     build_from_nightly_release
   else