Repository: knative/client
Pull request #693 (2020-02-29 09:36:19)

Re-enable markdown link check
## Proposed Changes
* Re-enable markdown link check as https://github.com/raviqqe/liche/issues/33 is now fixed,
  see https://github.com/knative/test-infra/pull/1764/
* Update test-infra to latest

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

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

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

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

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

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

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->
navidshaikh: /cc @chizhg 
knative-prow-robot: @navidshaikh: The following test **failed**, say `/retest` to rerun all failed tests:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pull-knative-client-integration-tests-latest-release | 783661d88124730629ecd6c251df65575ca6eea6 | [link](https://prow.knative.dev/view/gcs/knative-prow/pr-logs/pull/knative_client/693/pull-knative-client-integration-tests-latest-release/1233687520609308673) | `/test pull-knative-client-integration-tests-latest-release`

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

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
navidshaikh: /retest

```
    cli.go:70: ERROR: Operation cannot be fulfilled on apiserversources.sources.eventing.knative.dev "testapisource3": the object has been modified; please apply your changes to the latest version and try again
```

Patch:
diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md
index 22b28a0c..23958aeb 100644
--- a/.github/ISSUE_TEMPLATE/bug-report.md
+++ b/.github/ISSUE_TEMPLATE/bug-report.md
@@ -1,44 +1,46 @@
 ---
 name: Bug report
-about: Report a bug in knative/client
+about: Report a bug for "kn"
 title: ''
 labels: kind/bug
 assignees: ''
 
 ---
 <!-- If you need to report a security issue with Knative, send an email to knative-security@googlegroups.com. -->
-## In what area(s)?
 
-<!-- Remove the '> ' to select -->
+### Bug report
 
-<!--
-Classifications:
-> /kind good-first-issue
-> /kind doc
-> /kind cleanup
--->
+<!-- Please describe what is actually happening -->
 
-## What version of Knative Client?
+### Expected behavior
 
-> Paste output of 'kn version'
+<!-- Please describe what you expect to happen -->
 
-## What version of Knative Serving running on your cluster?
+### Steps to reproduce the problem
 
-> 0.5.x
-> 0.6.x
-> 0.7.x
-> 0.8.x
+<!-- How can a maintainer reproduce this issue (please be detailed) -->
 
-## Expected Behavior
+### kn version
 
-<!-- Briefly describe what you expect to happen -->
+<!-- Please paste the output of 'kn version' in the code block below -->
 
+```
 
-## Actual Behavior
+```
 
-<!-- Briefly describe what is actually happening -->
+### Knative (serving/eventing) version
 
+<!-- Remove all except the known affected versions of Knative running on the cluster on which you have detected the issue -->
 
-## Steps to Reproduce the Problem
+> Nightly
+> 0.12.x
+> 0.11.x
+> 0.10.x
+> 0.9.x
 
-<!-- How can a maintainer reproduce this issue (be detailed) -->
+<!--
+Optional classifications: Remove ">" to add corresponding label
+> /kind good-first-issue
+> /kind doc
+> /kind cleanup
+-->
diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md
index 52f29b21..8bcff984 100644
--- a/.github/ISSUE_TEMPLATE/feature-request.md
+++ b/.github/ISSUE_TEMPLATE/feature-request.md
@@ -1,24 +1,33 @@
 ---
 name: Feature Request
-about: Create a feature request for knative/client
+about: Request a new feature for "kn"
 title: ''
 labels: kind/feature
 assignees: ''
 
 ---
 <!-- If you need to report a security issue with Knative, send an email to knative-security@googlegroups.com. -->
-## In what area(s)?
 
-<!-- Remove the '> ' to select -->
+### Feature request
+
+<!-- Please describe the feature request and why you would like to have it -->
+
+### Use case
+
+<!-- Please add a concrete use case to demonstrate how suhc a feature would add value for the user. If you don't have a use case for your feature, please remove this section (however providing a good use case increases the likelihood to be picked up) -->
+
+### UI Example
+
+<!-- If this is about a new command or command line options, please let us know how you would add it to the "kn" UI (in the code block below). If this is not applicable for your feature, delete this section. -->
+
+```
+
+```
 
 <!--
-Classifications:
+Optional Classifications, remove the '> ' to select:
 > /kind good-first-issue
-> /kind feature
 > /kind proposal
 > /kind doc
 > /kind cleanup
 -->
-
-## Describe the feature:
-
diff --git a/.github/ISSUE_TEMPLATE/ask-question.md b/.github/ISSUE_TEMPLATE/free-form.md
similarity index 50%
rename from .github/ISSUE_TEMPLATE/ask-question.md
rename to .github/ISSUE_TEMPLATE/free-form.md
index 82ee5426..4f3d3f2d 100644
--- a/.github/ISSUE_TEMPLATE/ask-question.md
+++ b/.github/ISSUE_TEMPLATE/free-form.md
@@ -1,23 +1,17 @@
 ---
-name: Question
-about: Ask a question about knative/client
+name: Free Form
+about: Create an unstructured issue.
 title: ''
-labels: kind/question
+labels: ''
 assignees: ''
 
 ---
 <!-- If you need to report a security issue with Knative, send an email to knative-security@googlegroups.com. -->
-## In what area(s)?
-
-<!-- Remove the '> ' to select -->
 
 <!--
-Classifications:
+Optional classifications (remove the '> ' to select)
+> /kind question
 > /kind good-first-issue
 > /kind usage
-> /kind compatibility
 > /kind doc
 -->
-
-## Ask your question here:
-
diff --git a/.github/pull-request-template.md b/.github/pull-request-template.md
index 573f738b..f45ccff0 100644
--- a/.github/pull-request-template.md
+++ b/.github/pull-request-template.md
@@ -1,28 +1,40 @@
-<!--
-Request Prow to automatically lint any go code in this PR:
 
-/lint
--->
+## Desciption
 
-Fixes #
+<!-- Please add a short summary about what the pull request is going to bring on the table -->
 
-## Proposed Changes
+## Changes
+
+<!-- Please add list of more detailed changes. These changes should be reflected also in the commit messages -->
 
 *
 *
 *
 
+## Reference
+
+<!-- Please add the corresponding issue number which this pull request is about to fix -->
+Fixes #
+
 <!--
-Release Note:
+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:
 
-- 🎁 Add new feature
-- 🐛 Fix bug
-- 🧽 Update or clean up current behaviour
+- 🎁 New feature
+- 🐛 Bug fix
+- ✨ Feature Update
+- 🐣 Refactoring
 - 🗑️ Remove feature or internal logic
 
-See other entries in CHANGELOG.adoc as an example.
+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
+-->
diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc
index d97c1ba2..1d542973 100644
--- a/CHANGELOG.adoc
+++ b/CHANGELOG.adoc
@@ -1,30 +1,28 @@
 # Changelog
 
-// Template:
-////
-[cols="1,10,3", options="header", width="100%"]
-|===
-| | Description | PR
+// Asciidoc template for a single table row. Copy the lines
+// within //// ... //// over into the current, unreleased version
+// table, select the proper icon (see legend at the bottom of this documents)
+// and adapt the link to point to your pull request. Please dont forget
+// the empty line separators.
 
-| 🎁🐛🧽🗑️
+////
+| 🎁🐛✨🐣🗑️
 |
 | https://github.com/knative/client/pull/[#]
-
-|===
 ////
 
-
 ## v0.13.0 (unreleased)
 
 [cols="1,10,3", options="header", width="100%"]
 |===
 | | Description | PR
 
-| 🧽
+| ✨
 | Allow configuration sink prefixes
 | https://github.com/knative/client/pull/571[#571]
 
-| 🧽
+| ✨
 | Support multiple revisions on `kn revision delete`
 | https://github.com/knative/client/pull/657[#657]
 
@@ -44,11 +42,11 @@
 | Add `--cmd` and `--arg` for customization of container entrypoint
 | https://github.com/knative/client/pull/635[#635]
 
-| 🧽
+| ✨
 | Add `no-wait` instead of `--async` and deprecate it
 | https://github.com/knative/client/pull/639[#639]
 
-| 🧽
+| ✨
 | Refactor service `create_test.go` and `update_test.go` to remove unecessary `sync` parameter in setup call
 | https://github.com/knative/client/pull/656[#656]
 
@@ -56,8 +54,8 @@
 | Fix `--image` flag to only allow single occurence
 | https://github.com/knative/client/pull/647[#647]
 
-| 🧽
-| Add `--wait` and `--no-wait` to service delete operation. Change service delete to wait by default.   
+| ✨
+| Add `--wait` and `--no-wait` to service delete operation. Change service delete to wait by default.
 | https://github.com/knative/client/pull/682[#682]
 
 | 🎁
@@ -79,7 +77,7 @@
 | Update to Knative eventing v0.12.0
 | https://github.com/knative/client/pull/621[#621]
 
-| 🧽️
+| ✨️
 | Update to Knative serving v0.12.0
 | https://github.com/knative/client/pull/618[#618]
 
@@ -87,7 +85,7 @@
 | Add `--pull-secret` for specifying pull secrets
 | https://github.com/knative/client/pull/617[#617]
 
-| 🧽
+| ✨
 | Improve error handling when no command is given
 | https://github.com/knative/client/pull/615[#615]
 
@@ -95,7 +93,7 @@
 | Add `--autoscale-window` for service commands
 | https://github.com/knative/client/pull/614[#614]
 
-| 🧽
+| ✨
 | Add checks for namespace creation instead of waiting
 | https://github.com/knative/client/pull/611[#611]
 
@@ -156,15 +154,15 @@
 | Add `kn source apiserver create/delete/update/describe` for managing ApiServer sources
 | https://github.com/knative/client/pull/556[#556]
 
-| 🧽
+| ✨
 | Update to Knative eventing dependency to 0.11.0
 | https://github.com/knative/client/pull/546[#546]
 
-| 🧽
+| ✨
 | Update to Knative serving dependency to 0.11.0
 | https://github.com/knative/client/pull/545[#545]
 
-| 🧽
+| ✨
 | Move cluster URL to `--verbose` for `service describe`
 | https://github.com/knative/client/pull/543[#543]
 
@@ -192,15 +190,15 @@
 | Add CI tests for using Kn with Tekton
 | https://github.com/knative/client/pull/528[#528]
 
-| 🧽
+| ✨
 | Update version information for eventing dependencies
 | https://github.com/knative/client/pull/495[#495]
 
-| 🧽
+| ✨
 | Support multiple NAMEs on kn service delete
 | https://github.com/knative/client/pull/492[#492]
 
-| 🧽
+| ✨
 | Add polling fallback for watching on service readiness
 | https://github.com/knative/client/pull/491[#491]
 
@@ -215,7 +213,7 @@
 |===
 | | Description | PR
 
-| 🧽
+| ✨
 | Update Knative serving dependency to 0.10.0
 | https://github.com/knative/client/pull/474[#474]
 
@@ -242,11 +240,11 @@
 |===
 | | Description | PR
 
-| 🧽
+| ✨
 | Update to Knative serving dependency to 0.9.0
 | https://github.com/knative/client/pull/458[#458]
 
-| 🧽
+| ✨
 | Add revision information to service list
 | https://github.com/knative/client/pull/441[#441]
 
@@ -258,11 +256,11 @@
 | Update build.sh -w to add a message when compilation succeeded
 | https://github.com/knative/client/pull/432[#432]
 
-| 🧽
+| ✨
 | Add more progress information during service create/update
 | https://github.com/knative/client/pull/431[#431]
 
-| 🧽
+| ✨
 | Change plugins configuration name to use `-` (dash) instead of camel case
 | https://github.com/knative/client/pull/428[#428]
 
@@ -270,11 +268,11 @@
 | Add `--annotation` flag for service create and update
 | https://github.com/knative/client/pull/422[#422]
 
-| 🧽
+| ✨
 | Restructure documentation
 | https://github.com/knative/client/pull/421[#421]
 
-| 🧽
+| ✨
 | Refine `route list` output
 | https://github.com/knative/client/pull/407[#407]
 
@@ -290,11 +288,11 @@
 | Retain the request body when logging HTTP
 | https://github.com/knative/client/pull/378[#378]
 
-| 🧽
+| ✨
 | Adds support for building cross platform binaries
 | https://github.com/knative/client/pull/371[#371]
 
-| 🧽
+| ✨
 | Update `version` command shows supported Serving and API versions
 | https://github.com/knative/client/pull/370[#370]
 
@@ -314,7 +312,7 @@
 | Wrap help messages to terminal size
 | https://github.com/knative/client/pull/351[#351]
 
-| 🧽
+| ✨
 | Change bool flags to the paired `--foo` and `--no-foo` format
 | https://github.com/knative/client/pull/346[#346]
 
@@ -354,7 +352,7 @@
 | Report an error if no flag(s) set in service update
 | https://github.com/knative/client/pull/318[#318]
 
-| 🧽
+| ✨
 | Improve create service error message
 | https://github.com/knative/client/pull/312[#312]
 
@@ -417,7 +415,7 @@
 | Dynamically set GroupVersionKind via schema lookup
 | https://github.com/knative/client/pull/134[#134]
 
-| 🧽
+| ✨
 | Introduce a `KnClient` interface
 | https://github.com/knative/client/pull/134[#134]
 
@@ -429,7 +427,7 @@
 | Add `kn route list`
 | https://github.com/knative/client/pull/202[#202]
 
-| 🧽
+| ✨
 | Improved error message when no command is given
 | https://github.com/knative/client/pull/218[#218]
 
@@ -453,7 +451,7 @@
 | Add goimport to `build.sh`
 | https://github.com/knative/client/pull/186[#186]
 
-| 🧽
+| ✨
 | Wait for service to become ready with `kn service create`
 | https://github.com/knative/client/pull/156[#156]
 
@@ -461,19 +459,19 @@
 | Add shell based smoke tests
 | https://github.com/knative/client/pull/183[#183]
 
-| 🧽
+| ✨
 | Use current namespace from `.kube/config` as default
 | https://github.com/knative/client/pull/172[#172]
 
-| 🧽
+| ✨
 | Add `--force` to `kn service create` for replacing existing service
 | https://github.com/knative/client/pull/79[#79]
 
-| 🧽
+| ✨
 | Add `kn revision list --service <srv>`
 | https://github.com/knative/client/pull/194[#194]
 
-| 🧽
+| ✨
 | Add success message to `kn service update`
 | https://github.com/knative/client/pull/169[#169]
 
@@ -485,15 +483,15 @@
 | Add Golang based E2E tests
 | https://github.com/knative/client/pull/121[#121]
 
-| 🧽
+| ✨
 | Rename `kn revision get` to `kn revision list`
 | https://github.com/knative/client/pull/180[#180]
 
-| 🧽
+| ✨
 | Rename `kn service get` to `kn service list`
 | https://github.com/knative/client/pull/179[#179]
 
-| 🧽
+| ✨
 | Refactoring to use sub-packages
 | https://github.com/knative/client/pull/66[#66]
 
@@ -501,7 +499,7 @@
 | Add `--test`, `--fast`, `--update` to `build.sh`
 | https://github.com/knative/client/pull/149[#149]
 
-| 🧽️
+| ✨️
 | Update to Knative serving 0.6.0
 | https://github.com/knative/client/pull/129[#129]
 
@@ -545,7 +543,7 @@
 |===
 
 '''
-_Legend_ :  🎁 Feature - 🐛 Fix - 🧽 Update - 🗑️ Remove
+_Legend_ :  🎁 Feature - 🐛 Fix - ✨ Update - 🐣 Refactoring - 🗑️ Remove
 
 ////
 ---------------------------------------------
@@ -555,3 +553,16 @@ Ignore PRs:
 45
 ---------------------------------------------
 ////
+
+// Asciidoc Template for a new release table. Add this after creating a release
+// to collect new changelog entries
+////
+
+## v0.XX.0 (unreleased)
+
+[cols="1,10,3", options="header", width="100%"]
+|===
+| | Description | PR
+
+|===
+////
diff --git a/README.md b/README.md
index e2ca3b30..f8d6be28 100644
--- a/README.md
+++ b/README.md
@@ -1,42 +1,36 @@
-# Knative Client
+# Kn
 
-This section outlines best practices for the Knative developer experience. It is a reference for Knative CLI implementation, and a reference for Knative client libraries.
+The Knative client `kn` is your door to the [Knative](https://knative.dev) world.
+It allows you to create Knative resources interactively from the command line or from within Shell scripts.
 
-The goals of the Knative Client are to:
+`kn` offers you:
 
-1. Follow the Knative [serving](https://github.com/knative/serving) and [eventing](https://github.com/knative/eventing) APIs
-2. Be scriptable to allow users to create different Knative workflows
-3. Expose useful Golang packages to allow integration into other programs or CLIs or plugins
-4. Use consistent verbs, nouns, and flags for various commands
-5. Be easily extended via a plugin mechanism (similar to `kubectl`) to allow for experimentation and customization
+* Full support for managing all features of [Knative Serving](https://github.com/knative/serving) (services, revisions, traffic splits)
+* Growing support [Knative eventing](https://github.com/knative/eventing), closely following its development (managing of sources & triggers)
+* A plugin architecture similar to that of `kubectl` plugins
+* A thin client-specific API in golang which helps in tasks like synchronously waiting on Knative service write operations.
+* An easy integration of Knative into Tekton Pipelines by using [`kn` in a Tekton `Task`](https://github.com/tektoncd/catalog/tree/master/kn).
 
-# Docs
 
-Start with the [user's guide](docs/README.md) to learn more. You can read about common use cases, get detailed documentation on each command, and learn how to extend the `kn` CLI. For more information, access the following links:
+This client uses the [Knative Serving](https://github.com/knative/docs/blob/master/docs/serving/spec/knative-api-specification-1.0.md) and [Knative Eventing](https://github.com/knative/eventing/tree/master/docs/spec) API exclusively so that it will work with any Knative installation, even those that are not Kubernetes based.
+It does not help in *installing* Knative itself though.
+Please refer to the various [Knative installation options](https://knative.dev/docs/install/) for how to install Knative with its prerequisites.
 
-* [User's guide](docs/README.md)
-* [Generated documentation](docs/cmd/kn.md)
+## Documentation
 
-**Shell auto completion:**
+Start with the [user's guide](docs/README.md) to learn more. You can read about common use cases, get detailed documentation on each command, and learn how to extend the `kn` CLI. For more information, have a look at:
 
-Run the following command to enable shell auto-completion:
+* [User guide](docs/README.md)
+  - Installation - How to install `kn` and run on your machine
+  - Examples - Use case based examples
+  - FAQ (_to come._)
+* [Reference Manual](docs/cmd/kn.md) - all possible commands and options with usage examples
 
-For Zsh:
-```sh
-$ source <(kn completion zsh)
-```
+## Developers
 
-For Bash:
-```sh
-$ source <(kn completion bash)
-```
+We love contributions! Please refer to
+[CONTRIBUTING](https://knative.dev/contributing/) for more information on how to best contributed to contribute to Knative.
 
-Use TAB to list available sub-commands or flags.
+For code contributions it as easy as picking an [issue](https://github.com/knative/client/issues) (look out for "kind/good-first-issue"), briefly comment that you would like to work on it, code, test, code and finally submit a [PR](https://github.com/knative/client/pulls) which will trigger the review process.
 
-# Developers
-
-If you would like to contribute, please see
-[CONTRIBUTING](https://knative.dev/contributing/)
-for more information.
-
-To build `kn`, see our [Development](DEVELOPMENT.md) guide.
+More details on how to build and test can be found in the [Developer guide](docs/DEVELOPMENT.md).
diff --git a/DEVELOPMENT.md b/docs/DEVELOPMENT.md
similarity index 97%
rename from DEVELOPMENT.md
rename to docs/DEVELOPMENT.md
index da7781e6..b2c20328 100644
--- a/DEVELOPMENT.md
+++ b/docs/DEVELOPMENT.md
@@ -86,7 +86,7 @@ In the end, the build results in `kn` binary in your current directory, which ca
 
 **Testing:**
 
-Please follow the [guide](./test) here to test the `knative client`.
+Please follow the [guide](../test/README.md) here to test the `knative client`.
 
 **Notes:**
 
diff --git a/docs/cmd/kn_revision_delete.md b/docs/cmd/kn_revision_delete.md
index 037e941a..5d6f4e2c 100644
--- a/docs/cmd/kn_revision_delete.md
+++ b/docs/cmd/kn_revision_delete.md
@@ -21,8 +21,11 @@ kn revision delete NAME [flags]
 ### Options
 
 ```
+      --async              DEPRECATED: please use --no-wait instead. Delete revision and don't wait for it to be deleted.
   -h, --help               help for delete
   -n, --namespace string   Specify the namespace to operate in.
+      --no-wait            Delete revision and don't wait for it to be deleted.
+      --wait-timeout int   Seconds to wait before giving up on waiting for revision to be deleted. (default 600)
 ```
 
 ### Options inherited from parent commands
diff --git a/go.mod b/go.mod
index 09b20bed..6439cff3 100644
--- a/go.mod
+++ b/go.mod
@@ -23,7 +23,7 @@ require (
 	knative.dev/eventing v0.12.1-0.20200206203632-b0a7d8a77cc7
 	knative.dev/pkg v0.0.0-20200206191432-9072f494c940
 	knative.dev/serving v0.12.1-0.20200206201132-525b15d87dc1
-	knative.dev/test-infra v0.0.0-20200206203333-08d3515c0e1f
+	knative.dev/test-infra v0.0.0-20200229011351-4dac123b9a3d
 	sigs.k8s.io/yaml v1.1.0
 )
 
diff --git a/go.sum b/go.sum
index e9cd9100..bad85985 100644
--- a/go.sum
+++ b/go.sum
@@ -593,8 +593,8 @@ knative.dev/pkg v0.0.0-20200206191432-9072f494c940 h1:bbmIixxihewJeoxolF7jRgSzER
 knative.dev/pkg v0.0.0-20200206191432-9072f494c940/go.mod h1:pgODObA1dTyhNoFxPZTTjNWfx6F0aKsKzn+vaT9XO/Q=
 knative.dev/serving v0.12.1-0.20200206201132-525b15d87dc1 h1:fEj1JY8FwjyQ3bB7+nMGrKX/apOwIJOB7UVuLzIYkmA=
 knative.dev/serving v0.12.1-0.20200206201132-525b15d87dc1/go.mod h1:x2n255JS2XBI39tmjZ8CwTxIf9EKNMCrkVuiOttLRm0=
-knative.dev/test-infra v0.0.0-20200206203333-08d3515c0e1f h1:3zlcV5Q15wBr+h82Ys05O14rEQsIX3PBfiZVYrr0JGo=
-knative.dev/test-infra v0.0.0-20200206203333-08d3515c0e1f/go.mod h1:xcdUkMJrLlBswIZqL5zCuBFOC22WIPMQoVX1L35i0vQ=
+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=
 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/revision/delete.go b/pkg/kn/commands/revision/delete.go
index 3a856004..109448e8 100644
--- a/pkg/kn/commands/revision/delete.go
+++ b/pkg/kn/commands/revision/delete.go
@@ -17,6 +17,7 @@ package revision
 import (
 	"errors"
 	"fmt"
+	"time"
 
 	"github.com/spf13/cobra"
 
@@ -25,6 +26,8 @@ import (
 
 // NewRevisionDeleteCommand represent 'revision delete' command
 func NewRevisionDeleteCommand(p *commands.KnParams) *cobra.Command {
+	var waitFlags commands.WaitFlags
+
 	RevisionDeleteCommand := &cobra.Command{
 		Use:   "delete NAME",
 		Short: "Delete a revision.",
@@ -45,7 +48,11 @@ func NewRevisionDeleteCommand(p *commands.KnParams) *cobra.Command {
 			}
 
 			for _, name := range args {
-				err = client.DeleteRevision(name)
+				timeout := time.Duration(0)
+				if !waitFlags.NoWait {
+					timeout = time.Duration(waitFlags.TimeoutInSeconds) * time.Second
+				}
+				err = client.DeleteRevision(name, timeout)
 				if err != nil {
 					fmt.Fprintf(cmd.OutOrStdout(), "%s.\n", err)
 				} else {
@@ -56,5 +63,6 @@ func NewRevisionDeleteCommand(p *commands.KnParams) *cobra.Command {
 		},
 	}
 	commands.AddNamespaceFlags(RevisionDeleteCommand.Flags(), false)
+	waitFlags.AddConditionWaitFlags(RevisionDeleteCommand, commands.WaitDefaultTimeout, "Delete", "revision", "deleted")
 	return RevisionDeleteCommand
 }
diff --git a/pkg/serving/v1/client.go b/pkg/serving/v1/client.go
index 1a6c1def..003199be 100644
--- a/pkg/serving/v1/client.go
+++ b/pkg/serving/v1/client.go
@@ -89,7 +89,7 @@ type KnServingClient interface {
 	ListRevisions(opts ...ListConfig) (*servingv1.RevisionList, error)
 
 	// Delete a revision
-	DeleteRevision(name string) error
+	DeleteRevision(name string, timeout time.Duration) error
 
 	// Get a route by its unique name
 	GetRoute(name string) (*servingv1.Route, error)
@@ -177,6 +177,11 @@ func (cl *knServingClient) WatchService(name string, timeout time.Duration) (wat
 		cl.client.RESTClient(), cl.namespace, "services", name, timeout)
 }
 
+func (cl *knServingClient) WatchRevision(name string, timeout time.Duration) (watch.Interface, error) {
+	return wait.NewWatcher(cl.client.Revisions(cl.namespace).Watch,
+		cl.client.RESTClient(), cl.namespace, "revision", name, timeout)
+}
+
 // List services
 func (cl *knServingClient) ListServices(config ...ListConfig) (*servingv1.ServiceList, error) {
 	serviceList, err := cl.client.Services(cl.namespace).List(ListConfigs(config).toListOptions())
@@ -370,7 +375,25 @@ func getBaseRevision(cl KnServingClient, service *servingv1.Service) (*servingv1
 }
 
 // Delete a revision by name
-func (cl *knServingClient) DeleteRevision(name string) error {
+func (cl *knServingClient) DeleteRevision(name string, timeout time.Duration) error {
+	if timeout == 0 {
+		return cl.deleteRevision(name)
+	}
+	waitC := make(chan error)
+	go func() {
+		waitForEvent := wait.NewWaitForEvent("revision", cl.WatchRevision, func(evt *watch.Event) bool { return evt.Type == watch.Deleted })
+		err, _ := waitForEvent.Wait(name, timeout, wait.NoopMessageCallback())
+		waitC <- err
+	}()
+	err := cl.deleteRevision(name)
+	if err != nil {
+		return clienterrors.GetError(err)
+	}
+
+	return <-waitC
+}
+
+func (cl *knServingClient) deleteRevision(name string) error {
 	err := cl.client.Revisions(cl.namespace).Delete(name, &v1.DeleteOptions{})
 	if err != nil {
 		return clienterrors.GetError(err)
diff --git a/pkg/serving/v1/client_mock.go b/pkg/serving/v1/client_mock.go
index 9381ed34..c60583e7 100644
--- a/pkg/serving/v1/client_mock.go
+++ b/pkg/serving/v1/client_mock.go
@@ -146,12 +146,12 @@ func (c *MockKnServingClient) ListRevisions(opts ...ListConfig) (*servingv1.Revi
 }
 
 // Delete a revision
-func (sr *ServingRecorder) DeleteRevision(name interface{}, err error) {
-	sr.r.Add("DeleteRevision", []interface{}{name}, []interface{}{err})
+func (sr *ServingRecorder) DeleteRevision(name, timeout interface{}, err error) {
+	sr.r.Add("DeleteRevision", []interface{}{name, timeout}, []interface{}{err})
 }
 
-func (c *MockKnServingClient) DeleteRevision(name string) error {
-	call := c.recorder.r.VerifyCall("DeleteRevision", name)
+func (c *MockKnServingClient) DeleteRevision(name string, timeout time.Duration) error {
+	call := c.recorder.r.VerifyCall("DeleteRevision", name, timeout)
 	return mock.ErrorOrNil(call.Result[0])
 }
 
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 3a13617a..2d8799f8 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -714,7 +714,7 @@ knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1/fake
 knative.dev/serving/pkg/gc
 knative.dev/serving/pkg/network
 knative.dev/serving/pkg/reconciler/route/config
-# knative.dev/test-infra v0.0.0-20200206203333-08d3515c0e1f
+# knative.dev/test-infra v0.0.0-20200229011351-4dac123b9a3d
 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/revision/delete_test.go b/pkg/kn/commands/revision/delete_test.go
index 53ac70dd..66d5d9fb 100644
--- a/pkg/kn/commands/revision/delete_test.go
+++ b/pkg/kn/commands/revision/delete_test.go
@@ -15,14 +15,19 @@
 package revision
 
 import (
+	"errors"
 	"testing"
 
 	"gotest.tools/assert"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/apimachinery/pkg/watch"
 	clienttesting "k8s.io/client-go/testing"
 
 	"knative.dev/client/pkg/kn/commands"
 	"knative.dev/client/pkg/util"
+	"knative.dev/client/pkg/wait"
+	servingv1 "knative.dev/serving/pkg/apis/serving/v1"
 )
 
 func fakeRevisionDelete(args []string) (action clienttesting.Action, name string, output string, err error) {
@@ -35,6 +40,17 @@ func fakeRevisionDelete(args []string) (action clienttesting.Action, name string
 			name = deleteAction.GetName()
 			return true, nil, nil
 		})
+	fakeServing.AddWatchReactor("revisions",
+		func(a clienttesting.Action) (bool, watch.Interface, error) {
+			watchAction := a.(clienttesting.WatchAction)
+			_, found := watchAction.GetWatchRestrictions().Fields.RequiresExactMatch("metadata.name")
+			if !found {
+				return true, nil, errors.New("no field selector on metadata.name found")
+			}
+			w := wait.NewFakeWatch(getRevisionDeleteEvents("test-revision"))
+			w.Start()
+			return true, w, nil
+		})
 	cmd.SetArgs(args)
 	err = cmd.Execute()
 	if err != nil {
@@ -79,3 +95,10 @@ func TestMultipleRevisionDelete(t *testing.T) {
 	assert.Check(t, util.ContainsAll(output, "Revision", revName2, "deleted", "namespace", commands.FakeNamespace))
 	assert.Check(t, util.ContainsAll(output, "Revision", revName3, "deleted", "namespace", commands.FakeNamespace))
 }
+
+func getRevisionDeleteEvents(name string) []watch.Event {
+	return []watch.Event{
+		{watch.Added, &servingv1.Revision{ObjectMeta: metav1.ObjectMeta{Name: name}}},
+		{watch.Deleted, &servingv1.Revision{ObjectMeta: metav1.ObjectMeta{Name: name}}},
+	}
+}
diff --git a/pkg/serving/v1/client_mock_test.go b/pkg/serving/v1/client_mock_test.go
index 4bf80e52..ec85dd76 100644
--- a/pkg/serving/v1/client_mock_test.go
+++ b/pkg/serving/v1/client_mock_test.go
@@ -40,7 +40,7 @@ func TestMockKnClient(t *testing.T) {
 	recorder.WaitForService("hello", time.Duration(10)*time.Second, wait.NoopMessageCallback(), nil, 10*time.Second)
 	recorder.GetRevision("hello", nil, nil)
 	recorder.ListRevisions(mock.Any(), nil, nil)
-	recorder.DeleteRevision("hello", nil)
+	recorder.DeleteRevision("hello", time.Duration(10)*time.Second, nil)
 	recorder.GetRoute("hello", nil, nil)
 	recorder.ListRoutes(mock.Any(), nil, nil)
 	recorder.GetConfiguration("hello", nil, nil)
@@ -54,7 +54,7 @@ func TestMockKnClient(t *testing.T) {
 	client.WaitForService("hello", time.Duration(10)*time.Second, wait.NoopMessageCallback())
 	client.GetRevision("hello")
 	client.ListRevisions(WithName("blub"))
-	client.DeleteRevision("hello")
+	client.DeleteRevision("hello", time.Duration(10)*time.Second)
 	client.GetRoute("hello")
 	client.ListRoutes(WithName("blub"))
 	client.GetConfiguration("hello")
diff --git a/test/e2e/revision_test.go b/test/e2e/revision_test.go
index 45a7a9ee..bd0290c7 100644
--- a/test/e2e/revision_test.go
+++ b/test/e2e/revision_test.go
@@ -45,27 +45,25 @@ func TestRevision(t *testing.T) {
 	revName := test.findRevision(t, r, "hello")
 	test.revisionDescribeWithPrintFlags(t, r, revName)
 
-	t.Log("update hello service and increase the count of configuration generation")
+	t.Log("update hello service and increase revision count to 2")
 	test.serviceUpdate(t, r, "hello", "--env", "TARGET=kn", "--port", "8888")
 
 	t.Log("show a list of revisions sorted by the count of configuration generation")
 	test.revisionListWithService(t, r, "hello")
 
-	t.Log("delete latest revision from hello service and return no error")
-	revName = test.findRevision(t, r, "hello")
-	test.revisionDelete(t, r, revName)
-
-	t.Log("delete three revisions with one revision a nonexistent")
-
-	// increase count to 2 revisions
+	t.Log("update hello service and increase revision count to 3")
 	test.serviceUpdate(t, r, "hello", "--env", "TARGET=kn", "--port", "8888")
 
+	t.Log("delete three revisions with one revision a nonexistent")
 	existRevision1 := test.findRevisionByGeneration(t, r, "hello", 1)
 	existRevision2 := test.findRevisionByGeneration(t, r, "hello", 2)
 	nonexistRevision := "hello-nonexist"
-
 	test.revisionMultipleDelete(t, r, existRevision1, existRevision2, nonexistRevision)
 
+	t.Log("delete latest revision from hello service and return no error")
+	revName = test.findRevision(t, r, "hello")
+	test.revisionDelete(t, r, revName)
+
 	t.Log("delete hello service and return no error")
 	test.serviceDelete(t, r, "hello")
 }
diff --git a/test/e2e/service_options_test.go b/test/e2e/service_options_test.go
index 9e013916..6d26efd4 100644
--- a/test/e2e/service_options_test.go
+++ b/test/e2e/service_options_test.go
@@ -91,6 +91,12 @@ func TestServiceOptions(t *testing.T) {
 	test.validateContainerField(t, r, "svc5", "args", "[myArg1 --myArg2]")
 	test.serviceUpdate(t, r, "svc5", "--arg", "myArg1")
 	test.validateContainerField(t, r, "svc5", "args", "[myArg1]")
+
+	t.Log("create, update and validate service with user defined")
+	test.serviceCreateWithOptions(t, r, "svc6", "--user", "1001")
+	test.validateContainerField(t, r, "svc6", "securityContext.runAsUser", "1001")
+	test.serviceUpdate(t, r, "svc6", "--user", "1002")
+	test.validateContainerField(t, r, "svc6", "securityContext.runAsUser", "1002")
 }
 
 func (test *e2eTest) serviceCreateWithOptions(t *testing.T, r *KnRunResultCollector, serviceName string, options ...string) {
diff --git a/test/presubmit-tests.sh b/test/presubmit-tests.sh
index e6372883..76cb1649 100755
--- a/test/presubmit-tests.sh
+++ b/test/presubmit-tests.sh
@@ -32,8 +32,6 @@
 # Serving / Eventing of this specific version.
 
 export DISABLE_MD_LINTING=1
-# TODO: Enable markdown link check as https://github.com/raviqqe/liche/issues/33 is fixed
-export DISABLE_MD_LINK_CHECK=1
 export PRESUBMIT_TEST_FAIL_FAST=1
 
 export GO111MODULE=on
diff --git a/vendor/knative.dev/test-infra/scripts/README.md b/vendor/knative.dev/test-infra/scripts/README.md
index e6e9f3c7..ca673fb1 100644
--- a/vendor/knative.dev/test-infra/scripts/README.md
+++ b/vendor/knative.dev/test-infra/scripts/README.md
@@ -1,6 +1,6 @@
 # Helper scripts
 
-This directory contains helper scripts used by Prow test jobs, as well and local
+This directory contains helper scripts used by Prow test jobs, as well as local
 development scripts.
 
 ## Using the `presubmit-tests.sh` helper script
@@ -176,6 +176,9 @@ This is a helper script for Knative E2E test scripts. To use it:
    will immediately start the tests against the cluster currently configured for
    `kubectl`.
 
+1. By default `knative_teardown()` and `test_teardown()` will be called after
+   the tests finish, use `--skip-teardowns` if you don't want them to be called.
+
 1. By default Istio is installed on the cluster via Addon, use
    `--skip-istio-addon` if you choose not to have it preinstalled.
 
@@ -307,6 +310,9 @@ This is a helper script for Knative release scripts. To use it:
      if `--release-gcs` was passed, otherwise the default value
      `knative-nightly/<repo>` will be used. It is empty if `--publish` was not
      passed.
+   - `RELEASE_DIR`: contains the directory to store the manifests if
+     `--release-dir` was passed. Defaults to empty value, but if `--nopublish`
+     was passed then points to the repository root directory.
    - `BUILD_COMMIT_HASH`: the commit short hash for the current repo. If the
      current git tree is dirty, it will have `-dirty` appended to it.
    - `BUILD_YYYYMMDD`: current UTC date in `YYYYMMDD` format.
@@ -332,7 +338,7 @@ This is a helper script for Knative release scripts. To use it:
    All environment variables above, except `KO_FLAGS`, are marked read-only once
    `main()` is called (see below).
 
-1. Call the `main()` function passing `$@` (without quotes).
+1. Call the `main()` function passing `"$@"` (with quotes).
 
 ### Sample release script
 
@@ -345,5 +351,5 @@ function build_release() {
   ARTIFACTS_TO_PUBLISH="release.yaml"
 }
 
-main $@
+main "$@"
 ```
diff --git a/vendor/knative.dev/test-infra/scripts/e2e-tests.sh b/vendor/knative.dev/test-infra/scripts/e2e-tests.sh
index 3a2fa89a..a78920dc 100644
--- a/vendor/knative.dev/test-infra/scripts/e2e-tests.sh
+++ b/vendor/knative.dev/test-infra/scripts/e2e-tests.sh
@@ -231,9 +231,12 @@ function create_test_cluster() {
   [[ -n "${GCP_PROJECT}" ]] && test_cmd_args+=" --gcp-project ${GCP_PROJECT}"
   [[ -n "${E2E_SCRIPT_CUSTOM_FLAGS[@]}" ]] && test_cmd_args+=" ${E2E_SCRIPT_CUSTOM_FLAGS[@]}"
   local extra_flags=()
-  if (( IS_BOSKOS )); then # Add arbitrary duration, wait for Boskos projects acquisition before error out
+  if (( IS_BOSKOS )); then
+    # Add arbitrary duration, wait for Boskos projects acquisition before error out
     extra_flags+=(--boskos-wait-duration=20m)
-  else # Only let kubetest tear down the cluster if not using Boskos, it's done by Janitor if using Boskos
+  elif (( ! SKIP_TEARDOWNS )); then
+    # Only let kubetest tear down the cluster if not using Boskos and teardowns are not expected to be skipped,
+    # it's done by Janitor if using Boskos
     extra_flags+=(--down)
   fi
 
@@ -365,7 +368,8 @@ function setup_test_cluster() {
 
   export KO_DATA_PATH="${REPO_ROOT_DIR}/.git"
 
-  trap teardown_test_resources EXIT
+  # Do not run teardowns if we explicitly want to skip them.
+  (( ! SKIP_TEARDOWNS )) && trap teardown_test_resources EXIT
 
   # Handle failures ourselves, so we can dump useful info.
   set +o errexit
@@ -419,6 +423,7 @@ function fail_test() {
 RUN_TESTS=0
 SKIP_KNATIVE_SETUP=0
 SKIP_ISTIO_ADDON=0
+SKIP_TEARDOWNS=0
 GCP_PROJECT=""
 E2E_SCRIPT=""
 E2E_CLUSTER_VERSION=""
@@ -453,6 +458,7 @@ function initialize() {
     case ${parameter} in
       --run-tests) RUN_TESTS=1 ;;
       --skip-knative-setup) SKIP_KNATIVE_SETUP=1 ;;
+      --skip-teardowns) SKIP_TEARDOWNS=1 ;;
       --skip-istio-addon) SKIP_ISTIO_ADDON=1 ;;
       *)
         [[ $# -ge 2 ]] || abort "missing parameter after $1"
@@ -487,6 +493,7 @@ function initialize() {
   readonly EXTRA_CLUSTER_CREATION_FLAGS
   readonly EXTRA_KUBETEST_FLAGS
   readonly SKIP_KNATIVE_SETUP
+  readonly SKIP_TEARDOWNS
   readonly GKE_ADDONS
 
   if (( ! RUN_TESTS )); then
diff --git a/vendor/knative.dev/test-infra/scripts/library.sh b/vendor/knative.dev/test-infra/scripts/library.sh
index 0c921580..d2715650 100644
--- a/vendor/knative.dev/test-infra/scripts/library.sh
+++ b/vendor/knative.dev/test-infra/scripts/library.sh
@@ -135,8 +135,8 @@ function wait_until_pods_running() {
   local failed_pod=""
   for i in {1..150}; do  # timeout after 5 minutes
     local pods="$(kubectl get pods --no-headers -n $1 2>/dev/null)"
-    # All pods must be running
-    local not_running_pods=$(echo "${pods}" | grep -v Running | grep -v Completed)
+    # All pods must be running (ignore ImagePull error to allow the pod to retry)
+    local not_running_pods=$(echo "${pods}" | grep -v Running | grep -v Completed | grep -v ErrImagePull | grep -v ImagePullBackOff)
     if [[ -n "${pods}" ]] && [[ -z "${not_running_pods}" ]]; then
       # All Pods are running or completed. Verify the containers on each Pod.
       local all_ready=1
diff --git a/vendor/knative.dev/test-infra/scripts/presubmit-tests.sh b/vendor/knative.dev/test-infra/scripts/presubmit-tests.sh
index 85897acc..c14f2517 100644
--- a/vendor/knative.dev/test-infra/scripts/presubmit-tests.sh
+++ b/vendor/knative.dev/test-infra/scripts/presubmit-tests.sh
@@ -127,9 +127,9 @@ function report_build_test() {
 # Perform markdown build tests if necessary, unless disabled.
 function markdown_build_tests() {
   (( DISABLE_MD_LINTING && DISABLE_MD_LINK_CHECK )) && return 0
-  # Get changed markdown files (ignore /vendor and deleted files)
+  # Get changed markdown files (ignore /vendor, github templates, and deleted files)
   local mdfiles=""
-  for file in $(echo "${CHANGED_FILES}" | grep \.md$ | grep -v ^vendor/); do
+  for file in $(echo "${CHANGED_FILES}" | grep \.md$ | grep -v ^vendor/ | grep -v ^.github/); do
     [[ -f "${file}" ]] && mdfiles="${mdfiles} ${file}"
   done
   [[ -z "${mdfiles}" ]] && return 0
diff --git a/vendor/knative.dev/test-infra/scripts/release.sh b/vendor/knative.dev/test-infra/scripts/release.sh
index 8e19f2d0..915fc97f 100644
--- a/vendor/knative.dev/test-infra/scripts/release.sh
+++ b/vendor/knative.dev/test-infra/scripts/release.sh
@@ -93,9 +93,9 @@ RELEASE_VERSION=""
 RELEASE_NOTES=""
 RELEASE_BRANCH=""
 RELEASE_GCS_BUCKET="knative-nightly/${REPO_NAME}"
+RELEASE_DIR=""
 KO_FLAGS="-P"
 VALIDATION_TESTS="./test/presubmit-tests.sh"
-YAMLS_TO_PUBLISH=""
 ARTIFACTS_TO_PUBLISH=""
 FROM_NIGHTLY_RELEASE=""
 FROM_NIGHTLY_RELEASE_GCS=""
@@ -334,6 +334,7 @@ function find_latest_nightly() {
 function parse_flags() {
   local has_gcr_flag=0
   local has_gcs_flag=0
+  local has_dir_flag=0
   local is_dot_release=0
   local is_auto_release=0
 
@@ -365,8 +366,14 @@ function parse_flags() {
             ;;
           --release-gcs)
             RELEASE_GCS_BUCKET=$1
+            RELEASE_DIR=""
             has_gcs_flag=1
             ;;
+          --release-dir)
+            RELEASE_DIR=$1
+            RELEASE_GCS_BUCKET=""
+            has_dir_flag=1
+            ;;
           --version)
             [[ $1 =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || abort "version format must be '[0-9].[0-9].[0-9]'"
             RELEASE_VERSION=$1
@@ -389,6 +396,9 @@ function parse_flags() {
     shift
   done
 
+  (( has_gcs_flag )) && (( has_dir_flag )) && abort "cannot have both --release-gcs and --release-dir set simultaneously"
+  [[ -n "${RELEASE_GCS_BUCKET}" && -n "${RELEASE_DIR}" ]] && abort "cannot have both GCS and release directory set"
+
   # Do auto release unless release is forced
   if (( is_auto_release )); then
     (( is_dot_release )) && abort "cannot have both --dot-release and --auto-release set simultaneously"
@@ -422,8 +432,13 @@ function parse_flags() {
     (( has_gcr_flag )) && echo "Not publishing the release, GCR flag is ignored"
     (( has_gcs_flag )) && echo "Not publishing the release, GCS flag is ignored"
     KO_DOCKER_REPO="ko.local"
-    KO_FLAGS="-L ${KO_FLAGS}"
     RELEASE_GCS_BUCKET=""
+    [[ -z "${RELEASE_DIR}" ]] && RELEASE_DIR="${REPO_ROOT_DIR}"
+  fi
+
+  [[ -z "${RELEASE_GCS_BUCKET}" && -z "${RELEASE_DIR}" ]] && abort "--release-gcs or --release-dir must be used"
+  if [[ -n "${RELEASE_DIR}" ]]; then
+    mkdir -p "${RELEASE_DIR}" || abort "cannot create release dir '${RELEASE_DIR}'"
   fi
 
   # Get the commit, excluding any tags but keeping the "dirty" flag
@@ -450,6 +465,7 @@ function parse_flags() {
   readonly RELEASE_NOTES
   readonly RELEASE_BRANCH
   readonly RELEASE_GCS_BUCKET
+  readonly RELEASE_DIR
   readonly KO_DOCKER_REPO
   readonly VALIDATION_TESTS
   readonly FROM_NIGHTLY_RELEASE
@@ -458,22 +474,24 @@ function parse_flags() {
 # Run tests (unless --skip-tests was passed). Conveniently displays a banner indicating so.
 # Parameters: $1 - executable that runs the tests.
 function run_validation_tests() {
-  if (( ! SKIP_TESTS )); then
-    banner "Running release validation tests"
-    # Run tests.
-    if ! $1; then
-      banner "Release validation tests failed, aborting"
-      exit 1
-    fi
+  (( SKIP_TESTS )) && return
+  banner "Running release validation tests"
+  # Run tests.
+  if ! $1; then
+    banner "Release validation tests failed, aborting"
+    abort "release validation tests failed"
   fi
 }
 
-# Publishes the generated artifacts to GCS, GitHub, etc.
+# Publishes the generated artifacts to directory, GCS, GitHub, etc.
 # Parameters: $1..$n - files to add to the release.
 function publish_artifacts() {
   (( ! PUBLISH_RELEASE )) && return
   tag_images_in_yamls ${ARTIFACTS_TO_PUBLISH}
-  publish_to_gcs ${ARTIFACTS_TO_PUBLISH}
+  if [[ -n "${RELEASE_DIR}" ]]; then
+    cp ${ARTIFACTS_TO_PUBLISH} ${RELEASE_DIR} || abort "cannot copy release to '${RELEASE_DIR}'"
+  fi
+  [[ -n "${RELEASE_GCS_BUCKET}" ]] && publish_to_gcs ${ARTIFACTS_TO_PUBLISH}
   publish_to_github ${ARTIFACTS_TO_PUBLISH}
   banner "New release published successfully"
 }
@@ -482,7 +500,7 @@ function publish_artifacts() {
 function main() {
   function_exists build_release || abort "function 'build_release()' not defined"
   [[ -x ${VALIDATION_TESTS} ]] || abort "test script '${VALIDATION_TESTS}' doesn't exist"
-  parse_flags $@
+  parse_flags "$@"
   # Log what will be done and where.
   banner "Release configuration"
   if which gcloud &>/dev/null ; then
@@ -498,7 +516,9 @@ function main() {
     echo "- Artifacts WILL NOT be tagged"
   fi
   if (( PUBLISH_RELEASE )); then
-    echo "- Release WILL BE published to '${RELEASE_GCS_BUCKET}'"
+    local dst="${RELEASE_DIR}"
+    [[ -z "${dst}" ]] && dst="${RELEASE_GCS_BUCKET}"
+    echo "- Release WILL BE published to '${dst}'"
   else
     echo "- Release will not be published"
   fi
@@ -527,8 +547,6 @@ function main() {
     build_from_source
     set +e +o pipefail
   fi
-  # TODO(adrcunha): Remove once all repos use ARTIFACTS_TO_PUBLISH.
-  [[ -z "${ARTIFACTS_TO_PUBLISH}" ]] && ARTIFACTS_TO_PUBLISH="${YAMLS_TO_PUBLISH}"
   [[ -z "${ARTIFACTS_TO_PUBLISH}" ]] && abort "no artifacts were generated"
   # Ensure no empty file will be published.
   for artifact in ${ARTIFACTS_TO_PUBLISH}; do