Repository: knative-sandbox/kn-plugin-func
Pull request #1106 (2022-07-11 23:23:05)

feat: add OpenShift related Annotations & Labels
Signed-off-by: Zbynek Roubalik <zroubalik@gmail.com>

<!-- Thanks for sending a pull request! -->

# Changes

<!-- 
Describe your changes here- ideally you can get that description straight from
your descriptive commit message(s)! 

- :gift: Add new feature
- :bug: Fix bug
- :broom: Update or clean up current behavior
- :wastebasket: Remove feature or internal logic
-->

- :gift: add OpenShift related Annotations & Labels

<!--
In addition, categorize the changes you're making using the "/kind" Prow command, example:

/kind <kind>

Supported kinds are: api-change, bug, cleanup, deprecation, removal, documentation, enhancement, performance

-->
/kind enhancement

This should enable some OpenShift Developer Console UX features (Pipeline and Git Repo references) for on cluster builds:
<img width="1487" alt="fn-pipeline-ui" src="https://user-images.githubusercontent.com/726523/178374813-4d9fbb91-4943-435f-a5f9-eb47aa14e4ae.png">

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

This pull-request has been approved by: *<a href="https://github.com/knative-sandbox/kn-plugin-func/pull/1106#" title="Author self-approved">zroubalik</a>*

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

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-sandbox/kn-plugin-func/blob/main/OWNERS)~~ [zroubalik]

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":[]} -->
zroubalik: @nainaz FYI
codecov[bot]: # [Codecov](https://codecov.io/gh/knative-sandbox/kn-plugin-func/pull/1106?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox) Report
> Merging [#1106](https://codecov.io/gh/knative-sandbox/kn-plugin-func/pull/1106?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox) (28872b8) into [main](https://codecov.io/gh/knative-sandbox/kn-plugin-func/commit/a197f8b330d6f5fdbc9c16585e605cdf74f9b8b9?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox) (a197f8b) will **decrease** coverage by `0.06%`.
> The diff coverage is `32.43%`.

```diff
@@            Coverage Diff             @@
##             main    #1106      +/-   ##
==========================================
- Coverage   44.91%   44.84%   -0.07%     
==========================================
  Files          64       64              
  Lines        8502     8553      +51     
==========================================
+ Hits         3819     3836      +17     
- Misses       4299     4332      +33     
- Partials      384      385       +1     
```


| [Impacted Files](https://codecov.io/gh/knative-sandbox/kn-plugin-func/pull/1106?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox) | Coverage Δ | |
|---|---|---|
| [knative/deployer.go](https://codecov.io/gh/knative-sandbox/kn-plugin-func/pull/1106/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox#diff-a25hdGl2ZS9kZXBsb3llci5nbw==) | `5.87% <0.00%> (-0.26%)` | :arrow_down: |
| [pipelines/tekton/pipeplines\_provider.go](https://codecov.io/gh/knative-sandbox/kn-plugin-func/pull/1106/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox#diff-cGlwZWxpbmVzL3Rla3Rvbi9waXBlcGxpbmVzX3Byb3ZpZGVyLmdv) | `0.00% <0.00%> (ø)` | |
| [cmd/client.go](https://codecov.io/gh/knative-sandbox/kn-plugin-func/pull/1106/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox#diff-Y21kL2NsaWVudC5nbw==) | `78.82% <80.00%> (-2.72%)` | :arrow_down: |
| [s2i/builder.go](https://codecov.io/gh/knative-sandbox/kn-plugin-func/pull/1106/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox#diff-czJpL2J1aWxkZXIuZ28=) | `64.23% <0.00%> (+1.15%)` | :arrow_up: |

------

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


Patch:
diff --git a/cmd/client.go b/cmd/client.go
index 43e8e00f..8080e0be 100644
--- a/cmd/client.go
+++ b/cmd/client.go
@@ -61,10 +61,12 @@ func NewClientFactory(n func() *fn.Client) ClientFactory {
 //   defer done()
 func NewClient(cfg ClientConfig, options ...fn.Option) (*fn.Client, func()) {
 	var (
-		p = progress.New(cfg.Verbose) // updates the CLI
-		t = newTransport()            // may provide a custom impl which proxies
-		c = newCredentialsProvider(t) // for accessing registries
-		o = []fn.Option{              // standard (shared) options for all commands
+		p  = progress.New(cfg.Verbose) // updates the CLI
+		t  = newTransport()            // may provide a custom impl which proxies
+		c  = newCredentialsProvider(t) // for accessing registries
+		d  = newKnativeDeployer(cfg.Namespace, cfg.Verbose)
+		pp = newTektonPipelinesProvider(cfg.Namespace, p, c, cfg.Verbose)
+		o  = []fn.Option{ // standard (shared) options for all commands
 			fn.WithVerbose(cfg.Verbose),
 			fn.WithProgressListener(p),
 			fn.WithTransport(t),
@@ -73,12 +75,8 @@ func NewClient(cfg ClientConfig, options ...fn.Option) (*fn.Client, func()) {
 			fn.WithDescriber(knative.NewDescriber(cfg.Namespace, cfg.Verbose)),
 			fn.WithLister(knative.NewLister(cfg.Namespace, cfg.Verbose)),
 			fn.WithRunner(docker.NewRunner(cfg.Verbose)),
-			fn.WithDeployer(knative.NewDeployer(cfg.Namespace, cfg.Verbose)),
-			fn.WithPipelinesProvider(tekton.NewPipelinesProvider(
-				tekton.WithNamespace(cfg.Namespace),
-				tekton.WithProgressListener(p),
-				tekton.WithCredentialsProvider(c),
-				tekton.WithVerbose(cfg.Verbose))),
+			fn.WithDeployer(d),
+			fn.WithPipelinesProvider(pp),
 			fn.WithPusher(docker.NewPusher(
 				docker.WithCredentialsProvider(c),
 				docker.WithProgressListener(p),
@@ -132,6 +130,35 @@ func newCredentialsProvider(t http.RoundTripper) docker.CredentialsProvider {
 	return creds.NewCredentialsProvider(options...)
 }
 
+func newTektonPipelinesProvider(namespace string, progress *progress.Bar, creds docker.CredentialsProvider, verbose bool) *tekton.PipelinesProvider {
+	options := []tekton.Opt{
+		tekton.WithNamespace(namespace),
+		tekton.WithProgressListener(progress),
+		tekton.WithCredentialsProvider(creds),
+		tekton.WithVerbose(verbose),
+	}
+
+	if openshift.IsOpenShift() {
+		options = append(options, tekton.WithPipelineDecorator(openshift.OpenshiftMetadataDecorator{}))
+	}
+
+	return tekton.NewPipelinesProvider(options...)
+
+}
+
+func newKnativeDeployer(namespace string, verbose bool) fn.Deployer {
+	options := []knative.DeployerOpt{
+		knative.WithDeployerNamespace(namespace),
+		knative.WithDeployerVerbose(verbose),
+	}
+
+	if openshift.IsOpenShift() {
+		options = append(options, knative.WithDeployerDecorator(openshift.OpenshiftMetadataDecorator{}))
+	}
+
+	return knative.NewDeployer(options...)
+}
+
 func GetDefaultRegistry() string {
 	switch {
 	case openshift.IsOpenShift():
diff --git a/cmd/deploy.go b/cmd/deploy.go
index 219b7cfc..8881e4bb 100644
--- a/cmd/deploy.go
+++ b/cmd/deploy.go
@@ -63,7 +63,7 @@ that is pushed to an image registry, and finally the function's Knative service
 	// Flags shared with Build specifically related to building:
 	cmd.Flags().StringP("builder", "", "pack", "build strategy to use when creating the underlying image. Currently supported build strategies are 'pack' and 's2i'.")
 	cmd.Flags().StringP("builder-image", "", "", "builder image, either an as a an image name or a mapping name.\nSpecified value is stored in func.yaml (as 'builder' field) for subsequent builds. ($FUNC_BUILDER_IMAGE)")
-	cmd.Flags().StringP("image", "i", "", "Full image name in the form [registry]/[namespace]/[name]:[tag] (optional). This option takes precedence over --registry (Env: $FUNC_IMAGE)")
+	cmd.Flags().StringP("image", "i", "", "Full image name in the form [registry]/[namespace]/[name]:[tag]@[digest]. This option takes precedence over --registry. Specifying digest is optional, but if it is given, 'build' and 'push' phases are disabled. (Env: $FUNC_IMAGE)")
 	cmd.Flags().StringP("registry", "r", GetDefaultRegistry(), "Registry + namespace part of the image to build, ex 'quay.io/myuser'.  The full image name is automatically determined based on the local directory name. If not provided the registry will be taken from func.yaml (Env: $FUNC_REGISTRY)")
 	cmd.Flags().BoolP("push", "u", true, "Attempt to push the function image to registry before deploying (Env: $FUNC_PUSH)")
 	cmd.Flags().StringP("platform", "", "", "Target platform to build (e.g. linux/amd64).")
@@ -104,11 +104,27 @@ func runDeploy(cmd *cobra.Command, _ []string, newClient ClientFactory) (err err
 		return
 	}
 
+	//if --image contains '@', validate image digest and disable build and push if not set, otherwise return an error
+	imageSplit := strings.Split(config.Image, "@")
+	imageDigestProvided := false
+
+	if len(imageSplit) == 2 {
+		if config, err = parseImageDigest(imageSplit, config, cmd); err != nil {
+			return
+		}
+		imageDigestProvided = true
+	}
+
 	function, err := functionWithOverrides(config.Path, functionOverrides{Namespace: config.Namespace, Image: config.Image})
 	if err != nil {
 		return
 	}
 
+	// save image digest if provided in --image
+	if imageDigestProvided {
+		function.ImageDigest = imageSplit[1]
+	}
+
 	function.Envs, _, err = mergeEnvs(function.Envs, config.EnvToUpdate, config.EnvToRemove)
 	if err != nil {
 		return
@@ -500,3 +516,32 @@ func validateBuildType(buildType string) error {
 	}
 	return nil
 }
+
+func parseImageDigest(imageSplit []string, config deployConfig, cmd *cobra.Command) (deployConfig, error) {
+
+	if !strings.HasPrefix(imageSplit[1], "sha256:") {
+		return config, fmt.Errorf("value '%s' in --image has invalid prefix syntax for digest (should be 'sha256:')", config.Image)
+	}
+
+	if len(imageSplit[1][7:]) != 64 {
+		return config, fmt.Errorf("sha256 hash in '%s' from --image has the wrong length (%d), should be 64", imageSplit[1], len(imageSplit[1][7:]))
+	}
+
+	// if --build was set but not as 'disabled', return an error
+	if cmd.Flags().Changed("build") && config.BuildType != "disabled" {
+		return config, fmt.Errorf("the --build flag '%s' is not valid when using --image with digest", config.BuildType)
+	}
+
+	// if the --push flag was set by a user to 'true', return an error
+	if cmd.Flags().Changed("push") && config.Push {
+		return config, fmt.Errorf("the --push flag '%v' is not valid when using --image with digest", config.Push)
+	}
+
+	fmt.Printf("Deploying existing image with digest %s. Build and push are disabled.\n", imageSplit[1])
+
+	config.BuildType = "disabled"
+	config.Push = false
+	config.Image = imageSplit[0]
+
+	return config, nil
+}
diff --git a/docker/creds/credentials.go b/docker/creds/credentials.go
index a0d086f6..68ef1d06 100644
--- a/docker/creds/credentials.go
+++ b/docker/creds/credentials.go
@@ -32,30 +32,28 @@ var ErrUnauthorized = errors.New("bad credentials")
 
 var ErrCredentialsNotFound = errors.New("credentials not found")
 
-// VerifyCredentialsCallback checks if credentials are accepted by the registry.
+// VerifyCredentialsCallback checks if credentials are authorized for image push.
 // If credentials are incorrect this callback shall return ErrUnauthorized.
-type VerifyCredentialsCallback func(ctx context.Context, registry string, credentials docker.Credentials) error
+type VerifyCredentialsCallback func(ctx context.Context, image string, credentials docker.Credentials) error
 
-// CheckAuth verifies that credentials are correct
-func CheckAuth(ctx context.Context, registry string, credentials docker.Credentials, trans http.RoundTripper) error {
+// CheckAuth verifies that credentials can be used for image push
+func CheckAuth(ctx context.Context, image string, credentials docker.Credentials, trans http.RoundTripper) error {
 	authenticator := &authn.Basic{
 		Username: credentials.Username,
 		Password: credentials.Password,
 	}
 
-	reg, err := name.NewRegistry(registry)
+	ref, err := name.ParseReference(image)
 	if err != nil {
-		return err
-	}
-
-	serverAddress := registry
-	if !strings.HasPrefix(serverAddress, "https://") && !strings.HasPrefix(serverAddress, "http://") {
-		serverAddress = reg.Scheme() + "://" + serverAddress
+		return fmt.Errorf("cannot parse image reference: %w", err)
 	}
 
-	url := fmt.Sprintf("%s/v2/", serverAddress)
+	url := fmt.Sprintf("%s://%s/v2/%s/blobs/uploads/",
+		ref.Context().Registry.Scheme(),
+		ref.Context().RegistryStr(),
+		ref.Context().RepositoryStr())
 
-	tr, err := transport.NewWithContext(ctx, reg, authenticator, trans, nil)
+	tr, err := transport.NewWithContext(ctx, ref.Context().Registry, authenticator, trans, nil)
 	if err != nil {
 		var transportErr *transport.Error
 		if errors.As(err, &transportErr) && transportErr.StatusCode == 401 {
@@ -66,7 +64,7 @@ func CheckAuth(ctx context.Context, registry string, credentials docker.Credenti
 
 	cli := http.Client{Transport: tr}
 
-	req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
+	req, err := http.NewRequestWithContext(ctx, "POST", url, nil)
 	if err != nil {
 		return err
 	}
@@ -80,7 +78,7 @@ func CheckAuth(ctx context.Context, registry string, credentials docker.Credenti
 	switch {
 	case resp.StatusCode == http.StatusUnauthorized:
 		return ErrUnauthorized
-	case resp.StatusCode != http.StatusOK:
+	case resp.StatusCode < 200 || resp.StatusCode >= 300:
 		return fmt.Errorf("failed to verify credentials: status code: %d", resp.StatusCode)
 	default:
 		return nil
@@ -218,10 +216,17 @@ func NewCredentialsProvider(opts ...Opt) docker.CredentialsProvider {
 	return c.getCredentials
 }
 
-func (c *credentialsProvider) getCredentials(ctx context.Context, registry string) (docker.Credentials, error) {
+func (c *credentialsProvider) getCredentials(ctx context.Context, image string) (docker.Credentials, error) {
 	var err error
 	result := docker.Credentials{}
 
+	ref, err := name.ParseReference(image)
+	if err != nil {
+		return docker.Credentials{}, fmt.Errorf("cannot parse the image reference: %w", err)
+	}
+
+	registry := ref.Context().RegistryStr()
+
 	for _, load := range c.credentialLoaders {
 
 		result, err = load(registry)
@@ -233,7 +238,7 @@ func (c *credentialsProvider) getCredentials(ctx context.Context, registry strin
 			return docker.Credentials{}, err
 		}
 
-		err = c.verifyCredentials(ctx, registry, result)
+		err = c.verifyCredentials(ctx, image, result)
 		if err == nil {
 			return result, nil
 		} else {
@@ -254,7 +259,7 @@ func (c *credentialsProvider) getCredentials(ctx context.Context, registry strin
 			return docker.Credentials{}, err
 		}
 
-		err = c.verifyCredentials(ctx, registry, result)
+		err = c.verifyCredentials(ctx, image, result)
 		if err == nil {
 			err = setCredentialsByCredentialHelper(c.authFilePath, registry, result.Username, result.Password)
 			if err != nil {
diff --git a/docker/pusher.go b/docker/pusher.go
index c1273ea4..41679c29 100644
--- a/docker/pusher.go
+++ b/docker/pusher.go
@@ -31,7 +31,7 @@ type Credentials struct {
 	Password string
 }
 
-type CredentialsProvider func(ctx context.Context, registry string) (Credentials, error)
+type CredentialsProvider func(ctx context.Context, image string) (Credentials, error)
 
 // PusherDockerClient is sub-interface of client.CommonAPIClient required by pusher.
 type PusherDockerClient interface {
@@ -133,7 +133,7 @@ func (n *Pusher) Push(ctx context.Context, f fn.Function) (digest string, err er
 	}
 
 	n.progressListener.Stopping()
-	credentials, err := n.credentialsProvider(ctx, registry)
+	credentials, err := n.credentialsProvider(ctx, f.Image)
 	if err != nil {
 		return "", fmt.Errorf("failed to get credentials: %w", err)
 	}
diff --git a/go.mod b/go.mod
index 0fbd0b1a..4f626d4c 100644
--- a/go.mod
+++ b/go.mod
@@ -39,12 +39,11 @@ require (
 	k8s.io/apimachinery v0.23.5
 	k8s.io/client-go v1.5.2
 	k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9
-	knative.dev/client v0.29.0
-	knative.dev/eventing v0.29.2-0.20220420140829-ce4fe0990d23
-	knative.dev/hack v0.0.0-20220128200847-51a42b2eb63e
-	knative.dev/networking v0.0.0-20220120045035-ec849677a316 // indirect
-	knative.dev/pkg v0.0.0-20220222214439-083dd97300e1
-	knative.dev/serving v0.29.5
+	knative.dev/client v0.30.1
+	knative.dev/eventing v0.30.4-0.20220601140224-ec844245369e
+	knative.dev/hack v0.0.0-20220629135030-82afbd367967
+	knative.dev/pkg v0.0.0-20220314165618-a637a96a1bd9
+	knative.dev/serving v0.30.3-0.20220630163432-b5f775538f3d
 )
 
 replace (
diff --git a/go.sum b/go.sum
index e81a6804..562c698c 100644
--- a/go.sum
+++ b/go.sum
@@ -1324,10 +1324,10 @@ github.com/google/go-containerregistry v0.7.1-0.20211118220127-abdc633f8305/go.m
 github.com/google/go-containerregistry v0.7.1-0.20211203164431-c75901cce627/go.mod h1:IwJblnDNiCs8sxubbfPNniYsUqr8m+nt7YbPzecsGuE=
 github.com/google/go-containerregistry v0.8.0/go.mod h1:wW5v71NHGnQyb4k+gSshjxidrC7lN33MdWEn+Mz9TsI=
 github.com/google/go-containerregistry v0.8.1-0.20220110151055-a61fd0a8e2bb/go.mod h1:wW5v71NHGnQyb4k+gSshjxidrC7lN33MdWEn+Mz9TsI=
-github.com/google/go-containerregistry v0.8.1-0.20220120151853-ac864e57b117/go.mod h1:wW5v71NHGnQyb4k+gSshjxidrC7lN33MdWEn+Mz9TsI=
 github.com/google/go-containerregistry v0.8.1-0.20220202214207-9c35968ef47e/go.mod h1:cwx3SjrH84Rh9VFJSIhPh43ovyOp3DCWgY3h8nWmdGQ=
 github.com/google/go-containerregistry v0.8.1-0.20220211173031-41f8d92709b7/go.mod h1:cwx3SjrH84Rh9VFJSIhPh43ovyOp3DCWgY3h8nWmdGQ=
 github.com/google/go-containerregistry v0.8.1-0.20220216220642-00c59d91847c/go.mod h1:MMbnwuvLeZJRPqhTs8jDWc8xGlOs5YCGx1TSc/qdExk=
+github.com/google/go-containerregistry v0.8.1-0.20220219142810-1571d7fdc46e/go.mod h1:MMbnwuvLeZJRPqhTs8jDWc8xGlOs5YCGx1TSc/qdExk=
 github.com/google/go-containerregistry v0.8.1-0.20220414133640-f1b729141d33/go.mod h1:eTLvLZaEe2FoQsb25t7BLxQQryyrwHTzFfwxN87mhAw=
 github.com/google/go-containerregistry v0.8.1-0.20220414143355-892d7a808387 h1:GWICy4b02s8EA1M9H5krRQ48BKpIHO5LtBBm2BQLhx0=
 github.com/google/go-containerregistry v0.8.1-0.20220414143355-892d7a808387/go.mod h1:eTLvLZaEe2FoQsb25t7BLxQQryyrwHTzFfwxN87mhAw=
@@ -1471,7 +1471,6 @@ github.com/gostaticanalysis/testutil v0.3.1-0.20210208050101-bfb5c8eec0e4/go.mod
 github.com/gostaticanalysis/testutil v0.4.0/go.mod h1:bLIoPefWXrRi/ssLFWX1dx7Repi5x3CuviD3dgAZaBU=
 github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY=
 github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
-github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
 github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
 github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
 github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
@@ -2190,8 +2189,9 @@ github.com/prometheus/client_golang v1.6.0/go.mod h1:ZLOG9ck3JLRdB5MgO8f+lLTe83A
 github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
 github.com/prometheus/client_golang v1.9.0/go.mod h1:FqZLKOZnGdFAhOK4nqGHa7D66IdsO+O441Eve7ptJDU=
 github.com/prometheus/client_golang v1.10.0/go.mod h1:WJM3cc3yu7XKBKa/I8WeZm+V3eltZnBwfENSU7mdogU=
-github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ=
 github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
+github.com/prometheus/client_golang v1.11.1 h1:+4eQaD7vAZ6DsfsxB15hbE0odUjGI5ARs9yskGu1v4s=
+github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
 github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
@@ -3849,39 +3849,38 @@ k8s.io/utils v0.0.0-20220127004650-9b3446523e65/go.mod h1:jPW/WVKK9YHAvNhRxK0md/
 k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 h1:HNSDgDCrr/6Ly3WEGKZftiE7IY19Vz2GdbOCyI4qqhc=
 k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
 knative.dev/caching v0.0.0-20210803185815-4e553d2275a0/go.mod h1:Vs+HND39+KKaIQp9M3m3Jmt4YtznpitDQ3n53gxbDYQ=
-knative.dev/caching v0.0.0-20220118175933-0c1cc094a7f4/go.mod h1:OHsK3XaWmdi2/mPaNBiX8LbefbtM6TptnT90eVbYGSA=
-knative.dev/client v0.29.0 h1:VzmXYWNfzF5O1OUpCYv2rd8hj6Q3mwGNwOyx6y4G0g8=
-knative.dev/client v0.29.0/go.mod h1:VaTZlNkplns4UrscGPp4CwKcIVRcfC4Po1yRvfF4JiQ=
+knative.dev/caching v0.0.0-20220302153644-5a6403ef2de5/go.mod h1:52//2yvw0iO3Nu2duAMI5BzfQKHWiXZuvRvzaypoGkU=
+knative.dev/client v0.30.1 h1:Xg/48QnqlNehz8gnTP/ZxaWzTLz1jG5WQOBrANKOpWI=
+knative.dev/client v0.30.1/go.mod h1:j+eP1X09QnA1PmT3J+n3aUtvvXrrn8bvJ/3OHaYKwWI=
 knative.dev/eventing v0.25.0/go.mod h1:8jIsrnSONPgv+m63OTzpwZQJiQASYl77C3llCyYlBMU=
-knative.dev/eventing v0.29.0/go.mod h1:u5T5NZTDUsLR7yJwp5MDnBnDX5MhywD3yK3Rq+7gTtI=
-knative.dev/eventing v0.29.2-0.20220420140829-ce4fe0990d23 h1:9DucdcOalX90T2QMhQjh4MLjXUEgqgsRxuK1o1Tt+44=
-knative.dev/eventing v0.29.2-0.20220420140829-ce4fe0990d23/go.mod h1:u5T5NZTDUsLR7yJwp5MDnBnDX5MhywD3yK3Rq+7gTtI=
+knative.dev/eventing v0.30.0/go.mod h1:JCqC8evTls1WiBTmYhPEGME6OQD8HFnLQjFPImwOEOg=
+knative.dev/eventing v0.30.4-0.20220601140224-ec844245369e h1:AkKpJV9wpYbmq8RN1FzgI3klNulyiWVj9ELtBel8+k8=
+knative.dev/eventing v0.30.4-0.20220601140224-ec844245369e/go.mod h1:JCqC8evTls1WiBTmYhPEGME6OQD8HFnLQjFPImwOEOg=
 knative.dev/hack v0.0.0-20210622141627-e28525d8d260/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI=
-knative.dev/hack v0.0.0-20211122162614-813559cefdda/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI=
 knative.dev/hack v0.0.0-20211203062838-e11ac125e707/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI=
-knative.dev/hack v0.0.0-20220118141833-9b2ed8471e30/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI=
-knative.dev/hack v0.0.0-20220128200847-51a42b2eb63e h1:pW3LMToyFhAhbHQWQwUHLY57i7gjvyFwFC8Sg6oNkJ8=
 knative.dev/hack v0.0.0-20220128200847-51a42b2eb63e/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI=
+knative.dev/hack v0.0.0-20220224013837-e1785985d364/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI=
+knative.dev/hack v0.0.0-20220629135030-82afbd367967 h1:cQILmNUjgDZVI/3ubvubzZ2WR8elZZsCIPDtkLSUTsE=
+knative.dev/hack v0.0.0-20220629135030-82afbd367967/go.mod h1:PHt8x8yX5Z9pPquBEfIj0X66f8iWkWfR0S/sarACJrI=
 knative.dev/hack/schema v0.0.0-20210622141627-e28525d8d260/go.mod h1:ffjwmdcrH5vN3mPhO8RrF2KfNnbHeCE2C60A+2cv3U0=
-knative.dev/hack/schema v0.0.0-20220118141833-9b2ed8471e30/go.mod h1:ffjwmdcrH5vN3mPhO8RrF2KfNnbHeCE2C60A+2cv3U0=
+knative.dev/hack/schema v0.0.0-20220224013837-e1785985d364/go.mod h1:ffjwmdcrH5vN3mPhO8RrF2KfNnbHeCE2C60A+2cv3U0=
 knative.dev/networking v0.0.0-20210803181815-acdfd41c575c/go.mod h1:UA9m1M3rGssy63gVwjSh7CYoWTKZNO8cnY9QsIu7tyo=
-knative.dev/networking v0.0.0-20220120043934-ec785540a732/go.mod h1:6cKBV/h/vIQWCPOkds/RvzUmMR8Vz6Dks2NWb0+3xks=
-knative.dev/networking v0.0.0-20220120045035-ec849677a316 h1:fHgHP3nnJSfq115RgTMYVHPQBsBKQYtjUVGhMT/VLaA=
-knative.dev/networking v0.0.0-20220120045035-ec849677a316/go.mod h1:+ozCw7PVf//G9+HOW04hfWnU8UJE5fmWAQkb+ieMaXY=
+knative.dev/networking v0.0.0-20220302134042-e8b2eb995165 h1:mkUDPTqfRPNhsUTVOH53IOx0Utzlfwl48t8lLc1bfL4=
+knative.dev/networking v0.0.0-20220302134042-e8b2eb995165/go.mod h1:EdQTSLl8BDeLLrC8pymGOiPMRAknFg+7oRO6MMUts94=
 knative.dev/pkg v0.0.0-20210803160015-21eb4c167cc5/go.mod h1:RPk5txNA3apR9X40D4MpUOP9/VqOG8CrtABWfOwGVS4=
-knative.dev/pkg v0.0.0-20211206113427-18589ac7627e/go.mod h1:E6B4RTjZyxe55a0kxOlnEHEl71zuG7gghnqYvNBKwBw=
 knative.dev/pkg v0.0.0-20211215065729-552319d4f55b/go.mod h1:hrD91/shO1o4KMZa4oWhnbRPmVJhvq86TLy/STF/qf8=
 knative.dev/pkg v0.0.0-20220104185830-52e42b760b54/go.mod h1:189cvGP0mwpqwZGFrLk5WuERIsNI/J6HuQ1CIX7SXxY=
-knative.dev/pkg v0.0.0-20220118160532-77555ea48cd4/go.mod h1:etVT7Tm8pSDf4RKhGk4r7j/hj3dNBpvT7bO6a6wpahs=
 knative.dev/pkg v0.0.0-20220131144930-f4b57aef0006/go.mod h1:bZMFTPDPHV3wXuiQ09UJuEGYYQnfpe81MCxNvsMAiJk=
-knative.dev/pkg v0.0.0-20220222214439-083dd97300e1 h1:p6MI/Rs9AZC5+qRvqX48njRjmFBYi4Y80q23efgJ+38=
-knative.dev/pkg v0.0.0-20220222214439-083dd97300e1/go.mod h1:etVT7Tm8pSDf4RKhGk4r7j/hj3dNBpvT7bO6a6wpahs=
+knative.dev/pkg v0.0.0-20220228195509-fe264173447b/go.mod h1:SsH9J6Gz+CvrHmoL0TELJXmMmohqKSQ5bpJvCv+1+ZI=
+knative.dev/pkg v0.0.0-20220301181942-2fdd5f232e77/go.mod h1:SsH9J6Gz+CvrHmoL0TELJXmMmohqKSQ5bpJvCv+1+ZI=
+knative.dev/pkg v0.0.0-20220314165618-a637a96a1bd9 h1:a7VjID6wqPki2oMvXkisNqnhcNJN4H4ARWLa8ULyOng=
+knative.dev/pkg v0.0.0-20220314165618-a637a96a1bd9/go.mod h1:SsH9J6Gz+CvrHmoL0TELJXmMmohqKSQ5bpJvCv+1+ZI=
 knative.dev/reconciler-test v0.0.0-20210803183715-b61cc77c06f6/go.mod h1:+Kovy+G5zXZNcuO/uB+zfo37vFKZzsLIlWezt/nKMz0=
-knative.dev/reconciler-test v0.0.0-20220118183433-c8bfbe66bada/go.mod h1:XV4cghzCtdASkfUsfMYSnGfGRyd/naDjy9h7Tnae22g=
+knative.dev/reconciler-test v0.0.0-20220303141206-84821d26ed1f/go.mod h1:K5pZJkenonlT9o+MtRaNsBP7BazGwjhqYPepuV1zdnU=
 knative.dev/serving v0.25.0/go.mod h1:24E4fVyViFnz8aAaafzdrYKB7CAsQr4FMU7QXoIE6CI=
-knative.dev/serving v0.29.0/go.mod h1:8Ay9QjyTcqoJE+2PietSmT5/VMdSQHe5aIBhsAFOCjM=
-knative.dev/serving v0.29.5 h1:+NUjm2Npo43hWlQTkGsG89johEzIf9aiMKUsKfidzjA=
-knative.dev/serving v0.29.5/go.mod h1:00SLmEVPRwqtDPu4dXn2L8BVyvILurecO1z/v6oDAg0=
+knative.dev/serving v0.30.0/go.mod h1:UwsKXK4LnkM+e8/hhgJq2LtyzmzHD6UsrGPFe5JOBS8=
+knative.dev/serving v0.30.3-0.20220630163432-b5f775538f3d h1:jEaidfIVCyOxXx1lyBoqeitPeYyq2khsOJuwoK4ddLU=
+knative.dev/serving v0.30.3-0.20220630163432-b5f775538f3d/go.mod h1:eOV3X/ax+qGrZAj3SdoJjPrIin1KZWFGkfTeXGOgk3c=
 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/knative/deployer.go b/knative/deployer.go
index 78177268..3fa4f9a7 100644
--- a/knative/deployer.go
+++ b/knative/deployer.go
@@ -28,18 +28,48 @@ import (
 const LIVENESS_ENDPOINT = "/health/liveness"
 const READINESS_ENDPOINT = "/health/readiness"
 
+type DeployDecorator interface {
+	UpdateAnnotations(fn.Function, map[string]string) map[string]string
+	UpdateLabels(fn.Function, map[string]string) map[string]string
+}
+
+type DeployerOpt func(*Deployer)
+
 type Deployer struct {
 	// Namespace with which to override that set on the default configuration (such as the ~/.kube/config).
 	// If left blank, deployment will commence to the configured namespace.
 	Namespace string
 	// verbose logging enablement flag.
 	verbose bool
+
+	decorator DeployDecorator
+}
+
+func NewDeployer(opts ...DeployerOpt) *Deployer {
+	d := &Deployer{}
+
+	for _, opt := range opts {
+		opt(d)
+	}
+
+	return d
+}
+
+func WithDeployerNamespace(namespace string) DeployerOpt {
+	return func(d *Deployer) {
+		d.Namespace = namespace
+	}
+}
+
+func WithDeployerVerbose(verbose bool) DeployerOpt {
+	return func(d *Deployer) {
+		d.verbose = verbose
+	}
 }
 
-func NewDeployer(namespaceOverride string, verbose bool) *Deployer {
-	return &Deployer{
-		Namespace: namespaceOverride,
-		verbose:   verbose,
+func WithDeployerDecorator(decorator DeployDecorator) DeployerOpt {
+	return func(d *Deployer) {
+		d.decorator = decorator
 	}
 }
 
@@ -94,7 +124,7 @@ func (d *Deployer) Deploy(ctx context.Context, f fn.Function) (fn.DeploymentResu
 			referencedSecrets := sets.NewString()
 			referencedConfigMaps := sets.NewString()
 
-			service, err := generateNewService(f)
+			service, err := generateNewService(f, d.decorator)
 			if err != nil {
 				err = fmt.Errorf("knative deployer failed to generate the Knative Service: %v", err)
 				return fn.DeploymentResult{}, err
@@ -195,7 +225,7 @@ func (d *Deployer) Deploy(ctx context.Context, f fn.Function) (fn.DeploymentResu
 			return fn.DeploymentResult{}, err
 		}
 
-		_, err = client.UpdateServiceWithRetry(ctx, f.Name, updateService(f, newEnv, newEnvFrom, newVolumes, newVolumeMounts), 3)
+		_, err = client.UpdateServiceWithRetry(ctx, f.Name, updateService(f, newEnv, newEnvFrom, newVolumes, newVolumeMounts, d.decorator), 3)
 		if err != nil {
 			err = fmt.Errorf("knative deployer failed to update the Knative Service: %v", err)
 			return fn.DeploymentResult{}, err
@@ -240,7 +270,7 @@ func setHealthEndpoints(f fn.Function, c *corev1.Container) *corev1.Container {
 	return c
 }
 
-func generateNewService(f fn.Function) (*v1.Service, error) {
+func generateNewService(f fn.Function, decorator DeployDecorator) (*v1.Service, error) {
 	container := corev1.Container{
 		Image: f.ImageWithDigest(),
 	}
@@ -262,16 +292,21 @@ func generateNewService(f fn.Function) (*v1.Service, error) {
 	}
 	container.VolumeMounts = newVolumeMounts
 
-	labels, err := processLabels(f)
+	labels, err := processLabels(f, decorator)
 	if err != nil {
 		return nil, err
 	}
 
+	annotations := f.Annotations
+	if decorator != nil {
+		annotations = decorator.UpdateAnnotations(f, annotations)
+	}
+
 	service := &v1.Service{
 		ObjectMeta: metav1.ObjectMeta{
 			Name:        f.Name,
 			Labels:      labels,
-			Annotations: f.Annotations,
+			Annotations: annotations,
 		},
 		Spec: v1.ServiceSpec{
 			ConfigurationSpec: v1.ConfigurationSpec{
@@ -297,7 +332,7 @@ func generateNewService(f fn.Function) (*v1.Service, error) {
 	return service, nil
 }
 
-func updateService(f fn.Function, newEnv []corev1.EnvVar, newEnvFrom []corev1.EnvFromSource, newVolumes []corev1.Volume, newVolumeMounts []corev1.VolumeMount) func(service *v1.Service) (*v1.Service, error) {
+func updateService(f fn.Function, newEnv []corev1.EnvVar, newEnvFrom []corev1.EnvFromSource, newVolumes []corev1.Volume, newVolumeMounts []corev1.VolumeMount, decorator DeployDecorator) func(service *v1.Service) (*v1.Service, error) {
 	return func(service *v1.Service) (*v1.Service, error) {
 		// Removing the name so the k8s server can fill it in with generated name,
 		// this prevents conflicts in Revision name when updating the KService from multiple places.
@@ -305,6 +340,10 @@ func updateService(f fn.Function, newEnv []corev1.EnvVar, newEnvFrom []corev1.En
 
 		// Don't bother being as clever as we are with env variables
 		// Just set the annotations and labels to be whatever we find in func.yaml
+		if decorator != nil {
+			service.ObjectMeta.Annotations = decorator.UpdateAnnotations(f, service.ObjectMeta.Annotations)
+		}
+
 		for k, v := range f.Annotations {
 			service.ObjectMeta.Annotations[k] = v
 		}
@@ -328,7 +367,7 @@ func updateService(f fn.Function, newEnv []corev1.EnvVar, newEnvFrom []corev1.En
 			return service, err
 		}
 
-		labels, err := processLabels(f)
+		labels, err := processLabels(f, decorator)
 		if err != nil {
 			return service, err
 		}
@@ -354,7 +393,7 @@ func updateService(f fn.Function, newEnv []corev1.EnvVar, newEnvFrom []corev1.En
 //     value: value1
 //   - key: EXAMPLE2                            # Label from the local ENV var
 //     value: {{ env:MY_ENV }}
-func processLabels(f fn.Function) (map[string]string, error) {
+func processLabels(f fn.Function, decorator DeployDecorator) (map[string]string, error) {
 	labels := map[string]string{
 		labels.FunctionKey:        labels.FunctionValue,
 		labels.FunctionNameKey:    f.Name,
@@ -365,6 +404,11 @@ func processLabels(f fn.Function) (map[string]string, error) {
 		labels.DeprecatedFunctionRuntimeKey: f.Runtime,
 		// --- end of handling usage of deprecated runtime labels
 	}
+
+	if decorator != nil {
+		labels = decorator.UpdateLabels(f, labels)
+	}
+
 	for _, label := range f.Labels {
 		if label.Key != nil && label.Value != nil {
 			if strings.HasPrefix(*label.Value, "{{") {
diff --git a/openshift/metadata.go b/openshift/metadata.go
new file mode 100644
index 00000000..a8aee74b
--- /dev/null
+++ b/openshift/metadata.go
@@ -0,0 +1,38 @@
+package openshift
+
+import (
+	fn "knative.dev/kn-plugin-func"
+)
+
+const (
+	AnnotationOpenShiftVcsUri = "app.openshift.io/vcs-uri"
+	AnnotationOpenShiftVcsRef = "app.openshift.io/vcs-ref"
+
+	LabelAppK8sInstance = "app.kubernetes.io/instance"
+)
+
+type OpenshiftMetadataDecorator struct{}
+
+func (o OpenshiftMetadataDecorator) UpdateAnnotations(f fn.Function, annotations map[string]string) map[string]string {
+	if annotations == nil {
+		annotations = map[string]string{}
+	}
+	if f.Git.URL != nil {
+		annotations[AnnotationOpenShiftVcsUri] = *f.Git.URL
+	}
+	if f.Git.Revision != nil {
+		annotations[AnnotationOpenShiftVcsRef] = *f.Git.Revision
+	}
+
+	return annotations
+}
+
+func (o OpenshiftMetadataDecorator) UpdateLabels(f fn.Function, labels map[string]string) map[string]string {
+	if labels == nil {
+		labels = map[string]string{}
+	}
+
+	labels[LabelAppK8sInstance] = f.Name
+
+	return labels
+}
diff --git a/pipelines/resources/tekton/task/func-buildpacks/0.1/func-buildpacks.yaml b/pipelines/resources/tekton/task/func-buildpacks/0.1/func-buildpacks.yaml
index e17c917d..87d422c2 100644
--- a/pipelines/resources/tekton/task/func-buildpacks/0.1/func-buildpacks.yaml
+++ b/pipelines/resources/tekton/task/func-buildpacks/0.1/func-buildpacks.yaml
@@ -58,7 +58,9 @@ spec:
       default: "1000"
     - name: GROUP_ID
       description: The group ID of the builder image user.
-      default: "1000"
+      default: "0"
+      ##############################################################
+      #####  "default" has been changed to "0" for Knative Functions
     - name: PLATFORM_DIR
       description: The name of the platform directory.
       default: empty-dir
@@ -87,8 +89,8 @@ spec:
           chown -R "$(params.USER_ID):$(params.GROUP_ID)" "$(workspaces.cache.path)"
         fi
 
-        ############################################
-        #  "/emptyDir" has been added for Knative Functions
+        #######################################################
+        #####  "/emptyDir" has been added for Knative Functions
         for path in "/tekton/home" "/layers" "/emptyDir" "$(workspaces.source.path)"; do
           echo "> Setting permissions on '$path'..."
           chown -R "$(params.USER_ID):$(params.GROUP_ID)" "$path"
@@ -143,8 +145,8 @@ spec:
           mountPath: /layers
         - name: $(params.PLATFORM_DIR)
           mountPath: /platform
-          ############################################
-          #   "/emptyDir" has been added for Knative Functions
+          ########################################################
+          #####   "/emptyDir" has been added for Knative Functions
         - name: empty-dir
           mountPath: /emptyDir
 
@@ -176,7 +178,9 @@ spec:
           mountPath: /platform
       securityContext:
         runAsUser: 1000
-        runAsGroup: 1000
+        #################################################################
+        #####  "runAsGroup" has been changed to "0" for Knative Functions
+        runAsGroup: 0
 
     - name: results
       image: docker.io/library/bash:5.1.4@sha256:b208215a4655538be652b2769d82e576bc4d0a2bb132144c060efc5be8c3f5d6
@@ -213,8 +217,8 @@ spec:
       volumeMounts:
         - name: layers-dir
           mountPath: /layers
-          ############################################
-          #   "/emptyDir" has been added for Knative Functions
+          ########################################################
+          #####   "/emptyDir" has been added for Knative Functions
         - name: empty-dir
           mountPath: /emptyDir
 
diff --git a/pipelines/tekton/pipeplines_provider.go b/pipelines/tekton/pipeplines_provider.go
index 3b47b646..3f454259 100644
--- a/pipelines/tekton/pipeplines_provider.go
+++ b/pipelines/tekton/pipeplines_provider.go
@@ -24,6 +24,10 @@ import (
 	"knative.dev/pkg/apis"
 )
 
+type PipelineDecorator interface {
+	UpdateLabels(fn.Function, map[string]string) map[string]string
+}
+
 type Opt func(*PipelinesProvider)
 
 type PipelinesProvider struct {
@@ -33,6 +37,7 @@ type PipelinesProvider struct {
 	verbose             bool
 	progressListener    fn.ProgressListener
 	credentialsProvider docker.CredentialsProvider
+	decorator           PipelineDecorator
 }
 
 func WithNamespace(namespace string) Opt {
@@ -59,6 +64,12 @@ func WithVerbose(verbose bool) Opt {
 	}
 }
 
+func WithPipelineDecorator(decorator PipelineDecorator) Opt {
+	return func(pp *PipelinesProvider) {
+		pp.decorator = decorator
+	}
+}
+
 func NewPipelinesProvider(opts ...Opt) *PipelinesProvider {
 	pp := &PipelinesProvider{}
 
@@ -87,6 +98,9 @@ func (pp *PipelinesProvider) Run(ctx context.Context, f fn.Function) error {
 
 	// let's specify labels that will be applied to every resouce that is created for a Pipeline
 	labels := map[string]string{labels.FunctionNameKey: f.Name}
+	if pp.decorator != nil {
+		labels = pp.decorator.UpdateLabels(f, labels)
+	}
 
 	err = k8s.CreatePersistentVolumeClaim(ctx, getPipelinePvcName(f), pp.namespace, labels, corev1.ReadWriteOnce, *resource.NewQuantity(DefaultPersistentVolumeClaimSize, resource.DecimalSI))
 	if err != nil {
@@ -111,7 +125,7 @@ func (pp *PipelinesProvider) Run(ctx context.Context, f fn.Function) error {
 	}
 
 	pp.progressListener.Stopping()
-	creds, err := pp.credentialsProvider(ctx, registry)
+	creds, err := pp.credentialsProvider(ctx, f.Image)
 	if err != nil {
 		return err
 	}
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go
index 83c49b66..861b4d21 100644
--- a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go
+++ b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go
@@ -49,7 +49,10 @@ func InstrumentRoundTripperInFlight(gauge prometheus.Gauge, next http.RoundTripp
 // http.RoundTripper to observe the request result with the provided CounterVec.
 // The CounterVec must have zero, one, or two non-const non-curried labels. For
 // those, the only allowed label names are "code" and "method". The function
-// panics otherwise. Partitioning of the CounterVec happens by HTTP status code
+// panics otherwise. For the "method" label a predefined default label value set
+// is used to filter given values. Values besides predefined values will count
+// as `unknown` method.`WithExtraMethods` can be used to add more
+// methods to the set. Partitioning of the CounterVec happens by HTTP status code
 // and/or HTTP method if the respective instance label names are present in the
 // CounterVec. For unpartitioned counting, use a CounterVec with zero labels.
 //
@@ -57,13 +60,18 @@ func InstrumentRoundTripperInFlight(gauge prometheus.Gauge, next http.RoundTripp
 // is not incremented.
 //
 // See the example for ExampleInstrumentRoundTripperDuration for example usage.
-func InstrumentRoundTripperCounter(counter *prometheus.CounterVec, next http.RoundTripper) RoundTripperFunc {
+func InstrumentRoundTripperCounter(counter *prometheus.CounterVec, next http.RoundTripper, opts ...Option) RoundTripperFunc {
+	rtOpts := &option{}
+	for _, o := range opts {
+		o(rtOpts)
+	}
+
 	code, method := checkLabels(counter)
 
 	return RoundTripperFunc(func(r *http.Request) (*http.Response, error) {
 		resp, err := next.RoundTrip(r)
 		if err == nil {
-			counter.With(labels(code, method, r.Method, resp.StatusCode)).Inc()
+			counter.With(labels(code, method, r.Method, resp.StatusCode, rtOpts.extraMethods...)).Inc()
 		}
 		return resp, err
 	})
@@ -73,7 +81,10 @@ func InstrumentRoundTripperCounter(counter *prometheus.CounterVec, next http.Rou
 // http.RoundTripper to observe the request duration with the provided
 // ObserverVec.  The ObserverVec must have zero, one, or two non-const
 // non-curried labels. For those, the only allowed label names are "code" and
-// "method". The function panics otherwise. The Observe method of the Observer
+// "method". The function panics otherwise. For the "method" label a predefined
+// default label value set is used to filter given values. Values besides
+// predefined values will count as `unknown` method. `WithExtraMethods`
+// can be used to add more methods to the set. The Observe method of the Observer
 // in the ObserverVec is called with the request duration in
 // seconds. Partitioning happens by HTTP status code and/or HTTP method if the
 // respective instance label names are present in the ObserverVec. For
@@ -85,14 +96,19 @@ func InstrumentRoundTripperCounter(counter *prometheus.CounterVec, next http.Rou
 //
 // Note that this method is only guaranteed to never observe negative durations
 // if used with Go1.9+.
-func InstrumentRoundTripperDuration(obs prometheus.ObserverVec, next http.RoundTripper) RoundTripperFunc {
+func InstrumentRoundTripperDuration(obs prometheus.ObserverVec, next http.RoundTripper, opts ...Option) RoundTripperFunc {
+	rtOpts := &option{}
+	for _, o := range opts {
+		o(rtOpts)
+	}
+
 	code, method := checkLabels(obs)
 
 	return RoundTripperFunc(func(r *http.Request) (*http.Response, error) {
 		start := time.Now()
 		resp, err := next.RoundTrip(r)
 		if err == nil {
-			obs.With(labels(code, method, r.Method, resp.StatusCode)).Observe(time.Since(start).Seconds())
+			obs.With(labels(code, method, r.Method, resp.StatusCode, rtOpts.extraMethods...)).Observe(time.Since(start).Seconds())
 		}
 		return resp, err
 	})
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_server.go b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_server.go
index ab037db8..a23f0edc 100644
--- a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_server.go
+++ b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_server.go
@@ -45,7 +45,10 @@ func InstrumentHandlerInFlight(g prometheus.Gauge, next http.Handler) http.Handl
 // http.Handler to observe the request duration with the provided ObserverVec.
 // The ObserverVec must have valid metric and label names and must have zero,
 // one, or two non-const non-curried labels. For those, the only allowed label
-// names are "code" and "method". The function panics otherwise. The Observe
+// names are "code" and "method". The function panics otherwise. For the "method"
+// label a predefined default label value set is used to filter given values.
+// Values besides predefined values will count as `unknown` method.
+//`WithExtraMethods` can be used to add more methods to the set. The Observe
 // method of the Observer in the ObserverVec is called with the request duration
 // in seconds. Partitioning happens by HTTP status code and/or HTTP method if
 // the respective instance label names are present in the ObserverVec. For
@@ -58,7 +61,12 @@ func InstrumentHandlerInFlight(g prometheus.Gauge, next http.Handler) http.Handl
 //
 // Note that this method is only guaranteed to never observe negative durations
 // if used with Go1.9+.
-func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler) http.HandlerFunc {
+func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler, opts ...Option) http.HandlerFunc {
+	mwOpts := &option{}
+	for _, o := range opts {
+		o(mwOpts)
+	}
+
 	code, method := checkLabels(obs)
 
 	if code {
@@ -67,14 +75,14 @@ func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler) ht
 			d := newDelegator(w, nil)
 			next.ServeHTTP(d, r)
 
-			obs.With(labels(code, method, r.Method, d.Status())).Observe(time.Since(now).Seconds())
+			obs.With(labels(code, method, r.Method, d.Status(), mwOpts.extraMethods...)).Observe(time.Since(now).Seconds())
 		})
 	}
 
 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		now := time.Now()
 		next.ServeHTTP(w, r)
-		obs.With(labels(code, method, r.Method, 0)).Observe(time.Since(now).Seconds())
+		obs.With(labels(code, method, r.Method, 0, mwOpts.extraMethods...)).Observe(time.Since(now).Seconds())
 	})
 }
 
@@ -82,7 +90,10 @@ func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler) ht
 // to observe the request result with the provided CounterVec. The CounterVec
 // must have valid metric and label names and must have zero, one, or two
 // non-const non-curried labels. For those, the only allowed label names are
-// "code" and "method". The function panics otherwise. Partitioning of the
+// "code" and "method". The function panics otherwise. For the "method"
+// label a predefined default label value set is used to filter given values.
+// Values besides predefined values will count as `unknown` method.
+// `WithExtraMethods` can be used to add more methods to the set. Partitioning of the
 // CounterVec happens by HTTP status code and/or HTTP method if the respective
 // instance label names are present in the CounterVec. For unpartitioned
 // counting, use a CounterVec with zero labels.
@@ -92,20 +103,25 @@ func InstrumentHandlerDuration(obs prometheus.ObserverVec, next http.Handler) ht
 // If the wrapped Handler panics, the Counter is not incremented.
 //
 // See the example for InstrumentHandlerDuration for example usage.
-func InstrumentHandlerCounter(counter *prometheus.CounterVec, next http.Handler) http.HandlerFunc {
+func InstrumentHandlerCounter(counter *prometheus.CounterVec, next http.Handler, opts ...Option) http.HandlerFunc {
+	mwOpts := &option{}
+	for _, o := range opts {
+		o(mwOpts)
+	}
+
 	code, method := checkLabels(counter)
 
 	if code {
 		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 			d := newDelegator(w, nil)
 			next.ServeHTTP(d, r)
-			counter.With(labels(code, method, r.Method, d.Status())).Inc()
+			counter.With(labels(code, method, r.Method, d.Status(), mwOpts.extraMethods...)).Inc()
 		})
 	}
 
 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		next.ServeHTTP(w, r)
-		counter.With(labels(code, method, r.Method, 0)).Inc()
+		counter.With(labels(code, method, r.Method, 0, mwOpts.extraMethods...)).Inc()
 	})
 }
 
@@ -114,7 +130,10 @@ func InstrumentHandlerCounter(counter *prometheus.CounterVec, next http.Handler)
 // until the response headers are written. The ObserverVec must have valid
 // metric and label names and must have zero, one, or two non-const non-curried
 // labels. For those, the only allowed label names are "code" and "method". The
-// function panics otherwise. The Observe method of the Observer in the
+// function panics otherwise. For the "method" label a predefined default label
+// value set is used to filter given values. Values besides predefined values
+// will count as `unknown` method.`WithExtraMethods` can be used to add more
+// methods to the set. The Observe method of the Observer in the
 // ObserverVec is called with the request duration in seconds. Partitioning
 // happens by HTTP status code and/or HTTP method if the respective instance
 // label names are present in the ObserverVec. For unpartitioned observations,
@@ -128,13 +147,18 @@ func InstrumentHandlerCounter(counter *prometheus.CounterVec, next http.Handler)
 // if used with Go1.9+.
 //
 // See the example for InstrumentHandlerDuration for example usage.
-func InstrumentHandlerTimeToWriteHeader(obs prometheus.ObserverVec, next http.Handler) http.HandlerFunc {
+func InstrumentHandlerTimeToWriteHeader(obs prometheus.ObserverVec, next http.Handler, opts ...Option) http.HandlerFunc {
+	mwOpts := &option{}
+	for _, o := range opts {
+		o(mwOpts)
+	}
+
 	code, method := checkLabels(obs)
 
 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		now := time.Now()
 		d := newDelegator(w, func(status int) {
-			obs.With(labels(code, method, r.Method, status)).Observe(time.Since(now).Seconds())
+			obs.With(labels(code, method, r.Method, status, mwOpts.extraMethods...)).Observe(time.Since(now).Seconds())
 		})
 		next.ServeHTTP(d, r)
 	})
@@ -144,8 +168,11 @@ func InstrumentHandlerTimeToWriteHeader(obs prometheus.ObserverVec, next http.Ha
 // http.Handler to observe the request size with the provided ObserverVec. The
 // ObserverVec must have valid metric and label names and must have zero, one,
 // or two non-const non-curried labels. For those, the only allowed label names
-// are "code" and "method". The function panics otherwise. The Observe method of
-// the Observer in the ObserverVec is called with the request size in
+// are "code" and "method". The function panics otherwise. For the "method"
+// label a predefined default label value set is used to filter given values.
+// Values besides predefined values will count as `unknown` method.
+// `WithExtraMethods` can be used to add more methods to the set. The Observe
+// method of the Observer in the ObserverVec is called with the request size in
 // bytes. Partitioning happens by HTTP status code and/or HTTP method if the
 // respective instance label names are present in the ObserverVec. For
 // unpartitioned observations, use an ObserverVec with zero labels. Note that
@@ -156,7 +183,12 @@ func InstrumentHandlerTimeToWriteHeader(obs prometheus.ObserverVec, next http.Ha
 // If the wrapped Handler panics, no values are reported.
 //
 // See the example for InstrumentHandlerDuration for example usage.
-func InstrumentHandlerRequestSize(obs prometheus.ObserverVec, next http.Handler) http.HandlerFunc {
+func InstrumentHandlerRequestSize(obs prometheus.ObserverVec, next http.Handler, opts ...Option) http.HandlerFunc {
+	mwOpts := &option{}
+	for _, o := range opts {
+		o(mwOpts)
+	}
+
 	code, method := checkLabels(obs)
 
 	if code {
@@ -164,14 +196,14 @@ func InstrumentHandlerRequestSize(obs prometheus.ObserverVec, next http.Handler)
 			d := newDelegator(w, nil)
 			next.ServeHTTP(d, r)
 			size := computeApproximateRequestSize(r)
-			obs.With(labels(code, method, r.Method, d.Status())).Observe(float64(size))
+			obs.With(labels(code, method, r.Method, d.Status(), mwOpts.extraMethods...)).Observe(float64(size))
 		})
 	}
 
 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		next.ServeHTTP(w, r)
 		size := computeApproximateRequestSize(r)
-		obs.With(labels(code, method, r.Method, 0)).Observe(float64(size))
+		obs.With(labels(code, method, r.Method, 0, mwOpts.extraMethods...)).Observe(float64(size))
 	})
 }
 
@@ -179,8 +211,11 @@ func InstrumentHandlerRequestSize(obs prometheus.ObserverVec, next http.Handler)
 // http.Handler to observe the response size with the provided ObserverVec. The
 // ObserverVec must have valid metric and label names and must have zero, one,
 // or two non-const non-curried labels. For those, the only allowed label names
-// are "code" and "method". The function panics otherwise. The Observe method of
-// the Observer in the ObserverVec is called with the response size in
+// are "code" and "method". The function panics otherwise. For the "method"
+// label a predefined default label value set is used to filter given values.
+// Values besides predefined values will count as `unknown` method.
+// `WithExtraMethods` can be used to add more methods to the set. The Observe
+// method of the Observer in the ObserverVec is called with the response size in
 // bytes. Partitioning happens by HTTP status code and/or HTTP method if the
 // respective instance label names are present in the ObserverVec. For
 // unpartitioned observations, use an ObserverVec with zero labels. Note that
@@ -191,12 +226,18 @@ func InstrumentHandlerRequestSize(obs prometheus.ObserverVec, next http.Handler)
 // If the wrapped Handler panics, no values are reported.
 //
 // See the example for InstrumentHandlerDuration for example usage.
-func InstrumentHandlerResponseSize(obs prometheus.ObserverVec, next http.Handler) http.Handler {
+func InstrumentHandlerResponseSize(obs prometheus.ObserverVec, next http.Handler, opts ...Option) http.Handler {
+	mwOpts := &option{}
+	for _, o := range opts {
+		o(mwOpts)
+	}
+
 	code, method := checkLabels(obs)
+
 	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		d := newDelegator(w, nil)
 		next.ServeHTTP(d, r)
-		obs.With(labels(code, method, r.Method, d.Status())).Observe(float64(d.Written()))
+		obs.With(labels(code, method, r.Method, d.Status(), mwOpts.extraMethods...)).Observe(float64(d.Written()))
 	})
 }
 
@@ -290,7 +331,7 @@ func isLabelCurried(c prometheus.Collector, label string) bool {
 // unnecessary allocations on each request.
 var emptyLabels = prometheus.Labels{}
 
-func labels(code, method bool, reqMethod string, status int) prometheus.Labels {
+func labels(code, method bool, reqMethod string, status int, extraMethods ...string) prometheus.Labels {
 	if !(code || method) {
 		return emptyLabels
 	}
@@ -300,7 +341,7 @@ func labels(code, method bool, reqMethod string, status int) prometheus.Labels {
 		labels["code"] = sanitizeCode(status)
 	}
 	if method {
-		labels["method"] = sanitizeMethod(reqMethod)
+		labels["method"] = sanitizeMethod(reqMethod, extraMethods...)
 	}
 
 	return labels
@@ -330,7 +371,12 @@ func computeApproximateRequestSize(r *http.Request) int {
 	return s
 }
 
-func sanitizeMethod(m string) string {
+// If the wrapped http.Handler has a known method, it will be sanitized and returned.
+// Otherwise, "unknown" will be returned. The known method list can be extended
+// as needed by using extraMethods parameter.
+func sanitizeMethod(m string, extraMethods ...string) string {
+	// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods for
+	// the methods chosen as default.
 	switch m {
 	case "GET", "get":
 		return "get"
@@ -348,15 +394,25 @@ func sanitizeMethod(m string) string {
 		return "options"
 	case "NOTIFY", "notify":
 		return "notify"
+	case "TRACE", "trace":
+		return "trace"
+	case "PATCH", "patch":
+		return "patch"
 	default:
-		return strings.ToLower(m)
+		for _, method := range extraMethods {
+			if strings.EqualFold(m, method) {
+				return strings.ToLower(m)
+			}
+		}
+		return "unknown"
 	}
 }
 
 // If the wrapped http.Handler has not set a status code, i.e. the value is
-// currently 0, santizeCode will return 200, for consistency with behavior in
+// currently 0, sanitizeCode will return 200, for consistency with behavior in
 // the stdlib.
 func sanitizeCode(s int) string {
+	// See for accepted codes https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
 	switch s {
 	case 100:
 		return "100"
@@ -453,6 +509,9 @@ func sanitizeCode(s int) string {
 		return "511"
 
 	default:
-		return strconv.Itoa(s)
+		if s >= 100 && s <= 599 {
+			return strconv.Itoa(s)
+		}
+		return "unknown"
 	}
 }
diff --git a/vendor/github.com/prometheus/client_golang/prometheus/promhttp/option.go b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/option.go
new file mode 100644
index 00000000..35e41bd1
--- /dev/null
+++ b/vendor/github.com/prometheus/client_golang/prometheus/promhttp/option.go
@@ -0,0 +1,31 @@
+// Copyright 2022 The Prometheus Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package promhttp
+
+// Option are used to configure a middleware or round tripper..
+type Option func(*option)
+
+type option struct {
+	extraMethods []string
+}
+
+// WithExtraMethods adds additional HTTP methods to the list of allowed methods.
+// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods for the default list.
+//
+// See the example for ExampleInstrumentHandlerWithExtraMethods for example usage.
+func WithExtraMethods(methods ...string) Option {
+	return func(o *option) {
+		o.extraMethods = methods
+	}
+}
diff --git a/vendor/knative.dev/eventing/pkg/apis/eventing/v1/trigger_types.go b/vendor/knative.dev/eventing/pkg/apis/eventing/v1/trigger_types.go
index 2e15d545..e327fff0 100644
--- a/vendor/knative.dev/eventing/pkg/apis/eventing/v1/trigger_types.go
+++ b/vendor/knative.dev/eventing/pkg/apis/eventing/v1/trigger_types.go
@@ -169,10 +169,10 @@ type SubscriptionsAPIFilter struct {
 	// +optional
 	Suffix map[string]string `json:"suffix,omitempty"`
 
-	// SQL is a CloudEvents SQL expression that will be evaluated to true or false against each CloudEvent.
+	// CESQL is a CloudEvents SQL expression that will be evaluated to true or false against each CloudEvent.
 	//
 	// +optional
-	SQL string `json:"sql,omitempty"`
+	CESQL string `json:"cesql,omitempty"`
 }
 
 // TriggerFilterAttributes is a map of context attribute names to values for
diff --git a/vendor/knative.dev/eventing/pkg/apis/eventing/v1/trigger_validation.go b/vendor/knative.dev/eventing/pkg/apis/eventing/v1/trigger_validation.go
index ac033c1d..bcff34b9 100644
--- a/vendor/knative.dev/eventing/pkg/apis/eventing/v1/trigger_validation.go
+++ b/vendor/knative.dev/eventing/pkg/apis/eventing/v1/trigger_validation.go
@@ -23,9 +23,11 @@ import (
 	"regexp"
 
 	cesqlparser "github.com/cloudevents/sdk-go/sql/v2/parser"
+	"go.uber.org/zap"
 	corev1 "k8s.io/api/core/v1"
 	"knative.dev/pkg/apis"
 	"knative.dev/pkg/kmp"
+	"knative.dev/pkg/logging"
 
 	"knative.dev/eventing/pkg/apis/feature"
 )
@@ -198,6 +200,14 @@ func ValidateCESQLExpression(ctx context.Context, expression string) (errs *apis
 	if expression == "" {
 		return nil
 	}
+	// Need to recover in case Parse panics
+	defer func() {
+		if r := recover(); r != nil {
+			logging.FromContext(ctx).Debug("Warning! Calling CESQL Parser panicked. Treating expression as invalid.", zap.Any("recovered value", r), zap.String("CESQL", expression))
+			errs = apis.ErrInvalidValue(expression, apis.CurrentField)
+		}
+	}()
+
 	if _, err := cesqlparser.Parse(expression); err != nil {
 		return apis.ErrInvalidValue(expression, apis.CurrentField, err.Error())
 	}
@@ -223,7 +233,7 @@ func ValidateSubscriptionAPIFilter(ctx context.Context, filter *SubscriptionsAPI
 	).Also(
 		ValidateSubscriptionAPIFilter(ctx, filter.Not).ViaField("not"),
 	).Also(
-		ValidateCESQLExpression(ctx, filter.SQL).ViaField("sql"),
+		ValidateCESQLExpression(ctx, filter.CESQL).ViaField("cesql"),
 	)
 	return errs
 }
@@ -275,7 +285,7 @@ func hasMultipleDialects(filter *SubscriptionsAPIFilter) bool {
 			dialectFound = true
 		}
 	}
-	if filter.SQL != "" && dialectFound {
+	if filter.CESQL != "" && dialectFound {
 		return true
 	}
 	return false
diff --git a/vendor/knative.dev/hack/README.md b/vendor/knative.dev/hack/README.md
index 570f3709..de565f7c 100644
--- a/vendor/knative.dev/hack/README.md
+++ b/vendor/knative.dev/hack/README.md
@@ -111,7 +111,7 @@ main "$@"
 This is a helper script for Knative E2E test scripts. To use it:
 
 1. [optional] Customize the test cluster. Pass the flags as described
-   [here](../kntest/pkg/kubetest2/gke/README.md) to the `initialize` function
+   [here](../tools/kntest/pkg/kubetest2/gke/README.md) to the `initialize` function
    call if the default values don't fit your needs.
 
 1. Source the script.
diff --git a/vendor/knative.dev/hack/library.sh b/vendor/knative.dev/hack/library.sh
index 17ce662e..895800b3 100644
--- a/vendor/knative.dev/hack/library.sh
+++ b/vendor/knative.dev/hack/library.sh
@@ -544,26 +544,19 @@ function start_latest_eventing_sugar_controller() {
 }
 
 # Run a go tool, installing it first if necessary.
-# Parameters: $1 - tool package/dir for go get/install.
+# Parameters: $1 - tool package/dir for go install.
 #             $2 - tool to run.
 #             $3..$n - parameters passed to the tool.
 function run_go_tool() {
+  local package=$1
   local tool=$2
   local install_failed=0
+  # If no `@version` is provided, default to adding `@latest`
+  if [[ "$package" != *@* ]]; then
+    package=$package@latest
+  fi
   if [[ -z "$(which ${tool})" ]]; then
-    local action=get
-    [[ $1 =~ ^[\./].* ]] && action=install
-    # Avoid running `go get` from root dir of the repository, as it can change go.sum and go.mod files.
-    # See discussions in https://github.com/golang/go/issues/27643.
-    if [[ ${action} == "get" && $(pwd) == "${REPO_ROOT_DIR}" ]]; then
-      local temp_dir="$(mktemp -d)"
-      # Swallow the output as we are returning the stdout in the end.
-      pushd "${temp_dir}" > /dev/null 2>&1
-      GOFLAGS="" go ${action} "$1" || install_failed=1
-      popd > /dev/null 2>&1
-    else
-      GOFLAGS="" go ${action} "$1" || install_failed=1
-    fi
+    GOFLAGS="" go install "$package" || install_failed=1
   fi
   (( install_failed )) && return ${install_failed}
   shift 2
@@ -695,7 +688,7 @@ function go_mod_gopath_hack() {
 # Parameters: $1..$n - parameters passed to the tool.
 function run_kntest() {
   if [[ ! -x "$(command -v kntest)" ]]; then
-    echo "--- FAIL: kntest not installed, please clone knative test-infra repo and run \`go install ./kntest/cmd/kntest\` to install it"; return 1;
+    echo "--- FAIL: kntest not installed, please clone knative test-infra repo and run \`go install ./tools/kntest/cmd/kntest\` to install it"; return 1;
   fi
   kntest "$@"
 }
diff --git a/vendor/knative.dev/hack/release.sh b/vendor/knative.dev/hack/release.sh
index 6eb23299..0448a775 100644
--- a/vendor/knative.dev/hack/release.sh
+++ b/vendor/knative.dev/hack/release.sh
@@ -122,10 +122,10 @@ function git_push() {
    git push "${repo_url}" ${git_args} )
 }
 
-# Return the master version of a release.
+# Return the major+minor version of a release.
 # For example, "v0.2.1" returns "0.2"
 # Parameters: $1 - release version label.
-function master_version() {
+function major_minor_version() {
   local release="${1//v/}"
   local tokens=(${release//\./ })
   echo "${tokens[0]}.${tokens[1]}"
@@ -141,8 +141,7 @@ function hash_from_tag() {
 # Setup the repository upstream, if not set.
 function setup_upstream() {
   # hub and checkout need the upstream URL to be set
-  # TODO(adrcunha): Use "git remote get-url" once available on Prow.
-  local upstream="$(git config --get remote.upstream.url)"
+  local upstream="$(git remote get-url upstream)"
   echo "Remote upstream URL is '${upstream}'"
   if [[ -z "${upstream}" ]]; then
     echo "Setting remote upstream URL to '${REPO_UPSTREAM}'"
@@ -223,7 +222,7 @@ function prepare_dot_release() {
   if [[ -z "${RELEASE_BRANCH}" ]]; then
     echo "Last release is ${last_version}"
     # Determine branch
-    major_minor_version="$(master_version "${last_version}")"
+    major_minor_version="$(major_minor_version "${last_version}")"
     RELEASE_BRANCH="release-${major_minor_version}"
     echo "Last release branch is ${RELEASE_BRANCH}"
   else
@@ -235,13 +234,15 @@ function prepare_dot_release() {
   # Use the original tag (ie. potentially with a knative- prefix) when determining the last version commit sha
   local github_tag="$(hub_tool release | grep "${last_version}")"
   local last_release_commit="$(git rev-list -n 1 "${github_tag}")"
+  local last_release_commit_filtered="$(git rev-list --invert-grep --grep "\[skip-dot-release\]" -n 1 "${github_tag}")"
   local release_branch_commit="$(git rev-list -n 1 upstream/"${RELEASE_BRANCH}")"
+  local release_branch_commit_filtered="$(git rev-list --invert-grep --grep "\[skip-dot-release\]" -n 1 upstream/"${RELEASE_BRANCH}")"
   [[ -n "${last_release_commit}" ]] || abort "cannot get last release commit"
   [[ -n "${release_branch_commit}" ]] || abort "cannot get release branch last commit"
-  echo "Version ${last_version} is at commit ${last_release_commit}"
-  echo "Branch ${RELEASE_BRANCH} is at commit ${release_branch_commit}"
-  if [[ "${last_release_commit}" == "${release_branch_commit}" ]]; then
-    echo "*** Branch ${RELEASE_BRANCH} has no new cherry-picks since release ${last_version}"
+  echo "Version ${last_version} is at commit ${last_release_commit}. Comparing using ${last_release_commit_filtered}. If it is different is because commits with the [skip-dot-release] flag in their commit body are not being considered."
+  echo "Branch ${RELEASE_BRANCH} is at commit ${release_branch_commit}. Comparing using ${release_branch_commit_filtered}. If it is different is because commits with the [skip-dot-release] flag in their commit body are not being considered."
+  if [[ "${last_release_commit_filtered}" == "${release_branch_commit_filtered}" ]]; then
+    echo "*** Branch ${RELEASE_BRANCH} has no new cherry-picks (ignoring commits with [skip-dot-release]) since release ${last_version}."
     echo "*** No dot release will be generated, as no changes exist"
     exit 0
   fi
@@ -428,7 +429,7 @@ function parse_flags() {
     # TODO(adrcunha): "dot" releases from release branches require releasing nightlies
     # for such branches, which we don't do yet.
     [[ "${RELEASE_VERSION}" =~ ^[0-9]+\.[0-9]+\.0$ ]] || abort "version format must be 'X.Y.0'"
-    RELEASE_BRANCH="release-$(master_version "${RELEASE_VERSION}")"
+    RELEASE_BRANCH="release-$(major_minor_version "${RELEASE_VERSION}")"
     prepare_from_nightly_release
     setup_upstream
   fi
diff --git a/vendor/knative.dev/pkg/apis/url.go b/vendor/knative.dev/pkg/apis/url.go
index 89a4d245..e54cb1d0 100644
--- a/vendor/knative.dev/pkg/apis/url.go
+++ b/vendor/knative.dev/pkg/apis/url.go
@@ -27,6 +27,7 @@ import (
 // URL is an alias of url.URL.
 // It has custom json marshal methods that enable it to be used in K8s CRDs
 // such that the CRD resource will have the URL but operator code can can work with url.URL struct
+// +kubebuilder:validation:Type=string
 type URL url.URL
 
 // ParseURL attempts to parse the given string as a URL.
diff --git a/vendor/knative.dev/pkg/changeset/commit.go b/vendor/knative.dev/pkg/changeset/commit.go
index 52c77998..3668dfeb 100644
--- a/vendor/knative.dev/pkg/changeset/commit.go
+++ b/vendor/knative.dev/pkg/changeset/commit.go
@@ -17,6 +17,7 @@ limitations under the License.
 package changeset
 
 import (
+	"bufio"
 	"fmt"
 	"io/ioutil"
 	"os"
@@ -28,6 +29,10 @@ import (
 const (
 	commitIDFile      = "HEAD"
 	koDataPathEnvName = "KO_DATA_PATH"
+	// packedRefsFile is a file containing a list of refs, used to compact the
+	// list of refs instead of storing them on the filesystem directly.
+	// See https://git-scm.com/docs/git-pack-refs
+	packedRefsFile = "packed-refs"
 )
 
 var commitIDRE = regexp.MustCompile(`^[a-f0-9]{40}$`)
@@ -41,9 +46,27 @@ func Get() (string, error) {
 	}
 	commitID := strings.TrimSpace(string(data))
 	if rID := strings.TrimPrefix(commitID, "ref: "); rID != commitID {
+		// First try to read from the direct ref file - e.g. refs/heads/main
 		data, err := readFileFromKoData(rID)
 		if err != nil {
-			return "", err
+			if !os.IsNotExist(err) {
+				return "", err
+			}
+
+			// Ref file didn't exist - it might be contained in the packed-refs
+			// file.
+			var pferr error
+			data, pferr = findPackedRef(rID)
+			// Only return the sub-error if the packed-refs file exists, otherwise
+			// just let the original error return (e.g. treat it as if we didn't
+			// even attempt the operation). This is primarily to keep the error
+			// messages clean.
+			if pferr != nil {
+				if os.IsNotExist(pferr) {
+					return "", err
+				}
+				return "", pferr
+			}
 		}
 		commitID = strings.TrimSpace(string(data))
 	}
@@ -58,9 +81,49 @@ func Get() (string, error) {
 // to be wrapped into the container from /kodata by ko. If it fails, returns
 // the error it gets.
 func readFileFromKoData(filename string) ([]byte, error) {
+	f, err := koDataFile(filename)
+	if err != nil {
+		return nil, err
+	}
+	defer f.Close()
+	return ioutil.ReadAll(f)
+}
+
+// readFileFromKoData tries to open the file with given name under KO_DATA_PATH.
+// The file is expected to be wrapped into the container from /kodata by ko.
+// If it fails, returns the error it gets.
+func koDataFile(filename string) (*os.File, error) {
 	koDataPath := os.Getenv(koDataPathEnvName)
 	if koDataPath == "" {
 		return nil, fmt.Errorf("%q does not exist or is empty", koDataPathEnvName)
 	}
-	return ioutil.ReadFile(filepath.Join(koDataPath, filename))
+	return os.Open(filepath.Join(koDataPath, filename))
+}
+
+// findPackedRef searches the packed-ref file for ref values.
+// This can happen if the # of refs in a repo grows too much - git will try
+// and condense them into a file.
+// See https://git-scm.com/docs/git-pack-refs
+func findPackedRef(ref string) ([]byte, error) {
+	f, err := koDataFile(packedRefsFile)
+	if err != nil {
+		return nil, err
+	}
+	defer f.Close()
+
+	scanner := bufio.NewScanner(f)
+	for scanner.Scan() {
+		// We only care about lines with `<commit> <ref>` pairs.
+		// Why this might happen:
+		// 1. Lines starting with ^ refer to unpeeled tag SHAs
+		// 	  (e.g. the commits pointed to by annotated tags)
+		s := strings.Split(scanner.Text(), " ")
+		if len(s) != 2 {
+			continue
+		}
+		if ref == s[1] {
+			return []byte(s[0]), nil
+		}
+	}
+	return nil, fmt.Errorf("%q ref not found in packed-refs", ref)
 }
diff --git a/vendor/knative.dev/pkg/configmap/parse.go b/vendor/knative.dev/pkg/configmap/parse.go
index e93f9af2..e733e383 100644
--- a/vendor/knative.dev/pkg/configmap/parse.go
+++ b/vendor/knative.dev/pkg/configmap/parse.go
@@ -244,3 +244,24 @@ func Parse(data map[string]string, parsers ...ParseFunc) error {
 	}
 	return nil
 }
+
+// CollectMapEntriesWithPrefix parses the data into the target as a map[string]string, if it exists.
+// The map is represented as a list of key-value pairs with a common prefix.
+func CollectMapEntriesWithPrefix(prefix string, target *map[string]string) ParseFunc {
+	if target == nil {
+		panic("target cannot be nil")
+	}
+
+	return func(data map[string]string) error {
+		for k, v := range data {
+			if strings.HasPrefix(k, prefix) && len(k) > len(prefix)+1 {
+				if *target == nil {
+					m := make(map[string]string, 2)
+					*target = m
+				}
+				(*target)[k[len(prefix)+1: /* remove dot `.` */]] = v
+			}
+		}
+		return nil
+	}
+}
diff --git a/vendor/knative.dev/pkg/leaderelection/config.go b/vendor/knative.dev/pkg/leaderelection/config.go
index f07c30ce..11010014 100644
--- a/vendor/knative.dev/pkg/leaderelection/config.go
+++ b/vendor/knative.dev/pkg/leaderelection/config.go
@@ -56,6 +56,8 @@ func NewConfigFromMap(data map[string]string) (*Config, error) {
 		cm.AsDuration("retry-period", &config.RetryPeriod),
 
 		cm.AsUint32("buckets", &config.Buckets),
+
+		cm.CollectMapEntriesWithPrefix("map-lease-prefix", &config.LeaseNamesPrefixMapping),
 	); err != nil {
 		return nil, err
 	}
@@ -79,19 +81,21 @@ func NewConfigFromConfigMap(configMap *corev1.ConfigMap) (*Config, error) {
 // contained within a single namespace. Typically these will correspond to a
 // single source repository, viz: serving or eventing.
 type Config struct {
-	Buckets       uint32
-	LeaseDuration time.Duration
-	RenewDeadline time.Duration
-	RetryPeriod   time.Duration
+	Buckets                 uint32
+	LeaseDuration           time.Duration
+	RenewDeadline           time.Duration
+	RetryPeriod             time.Duration
+	LeaseNamesPrefixMapping map[string]string
 }
 
 func (c *Config) GetComponentConfig(name string) ComponentConfig {
 	return ComponentConfig{
-		Component:     name,
-		Buckets:       c.Buckets,
-		LeaseDuration: c.LeaseDuration,
-		RenewDeadline: c.RenewDeadline,
-		RetryPeriod:   c.RetryPeriod,
+		Component:               name,
+		Buckets:                 c.Buckets,
+		LeaseDuration:           c.LeaseDuration,
+		RenewDeadline:           c.RenewDeadline,
+		RetryPeriod:             c.RetryPeriod,
+		LeaseNamesPrefixMapping: c.LeaseNamesPrefixMapping,
 	}
 }
 
@@ -123,6 +127,11 @@ type ComponentConfig struct {
 	// be generated to be used as identity for each BuildElector call.
 	// Autoscaler uses the pod IP as identity.
 	Identity string
+
+	// LeaseNamesPrefixMapping maps lease prefixes
+	// from <component>.<package>.<reconciler_type_name> to the
+	// associated value when using standardBuilder.
+	LeaseNamesPrefixMapping map[string]string
 }
 
 // statefulSetID is a envconfig Decodable controller ordinal and name.
diff --git a/vendor/knative.dev/pkg/leaderelection/context.go b/vendor/knative.dev/pkg/leaderelection/context.go
index 4758ccba..4e4c46a4 100644
--- a/vendor/knative.dev/pkg/leaderelection/context.go
+++ b/vendor/knative.dev/pkg/leaderelection/context.go
@@ -27,6 +27,7 @@ import (
 	"k8s.io/client-go/kubernetes"
 	"k8s.io/client-go/tools/leaderelection"
 	"k8s.io/client-go/tools/leaderelection/resourcelock"
+
 	"knative.dev/pkg/hash"
 	"knative.dev/pkg/logging"
 	"knative.dev/pkg/network"
@@ -192,7 +193,11 @@ func newStandardBuckets(queueName string, cc ComponentConfig) []reconciler.Bucke
 }
 
 func standardBucketName(ordinal uint32, queueName string, cc ComponentConfig) string {
-	return strings.ToLower(fmt.Sprintf("%s.%s.%02d-of-%02d", cc.Component, queueName, ordinal, cc.Buckets))
+	prefix := fmt.Sprintf("%s.%s", cc.Component, queueName)
+	if v, ok := cc.LeaseNamesPrefixMapping[prefix]; ok && len(v) > 0 {
+		prefix = v
+	}
+	return strings.ToLower(fmt.Sprintf("%s.%02d-of-%02d", prefix, ordinal, cc.Buckets))
 }
 
 type statefulSetBuilder struct {
diff --git a/vendor/knative.dev/pkg/resolver/addressable_resolver.go b/vendor/knative.dev/pkg/resolver/addressable_resolver.go
index 0e50a257..d6995947 100644
--- a/vendor/knative.dev/pkg/resolver/addressable_resolver.go
+++ b/vendor/knative.dev/pkg/resolver/addressable_resolver.go
@@ -23,12 +23,14 @@ import (
 
 	"k8s.io/apimachinery/pkg/runtime/schema"
 	"k8s.io/client-go/tools/cache"
+
 	"knative.dev/pkg/client/injection/ducks/duck/v1/addressable"
 	"knative.dev/pkg/controller"
 
 	corev1 "k8s.io/api/core/v1"
 	apierrs "k8s.io/apimachinery/pkg/api/errors"
 	"k8s.io/apimachinery/pkg/api/meta"
+
 	"knative.dev/pkg/apis"
 	pkgapisduck "knative.dev/pkg/apis/duck"
 	duckv1 "knative.dev/pkg/apis/duck/v1"
@@ -169,17 +171,17 @@ func (r *URIResolver) URIFromObjectReference(ctx context.Context, ref *corev1.Ob
 		Namespace:  ref.Namespace,
 		Name:       ref.Name,
 	}, parent); err != nil {
-		return nil, apierrs.NewNotFound(gvr.GroupResource(), ref.Name)
+		return nil, fmt.Errorf("failed to track reference %s %s/%s: %w", gvr.String(), ref.Namespace, ref.Name, err)
 	}
 
 	lister, err := r.listerFactory(gvr)
 	if err != nil {
-		return nil, apierrs.NewNotFound(gvr.GroupResource(), "Lister")
+		return nil, fmt.Errorf("failed to get lister for %s: %w", gvr.String(), err)
 	}
 
 	obj, err := lister.ByNamespace(ref.Namespace).Get(ref.Name)
 	if err != nil {
-		return nil, apierrs.NewNotFound(gvr.GroupResource(), ref.Name)
+		return nil, fmt.Errorf("failed to get object %s/%s: %w", ref.Namespace, ref.Name, err)
 	}
 
 	// K8s Services are special cased. They can be called, even though they do not satisfy the
diff --git a/vendor/knative.dev/serving/pkg/apis/autoscaling/annotation_validation.go b/vendor/knative.dev/serving/pkg/apis/autoscaling/annotation_validation.go
index 307767a1..4a32d2af 100644
--- a/vendor/knative.dev/serving/pkg/apis/autoscaling/annotation_validation.go
+++ b/vendor/knative.dev/serving/pkg/apis/autoscaling/annotation_validation.go
@@ -109,7 +109,9 @@ func validateFloats(m map[string]string) (errs *apis.FieldError) {
 	}
 
 	if k, v, ok := TargetAnnotation.Get(m); ok {
-		if fv, err := strconv.ParseFloat(v, 64); err != nil || fv < TargetMin {
+		if fv, err := strconv.ParseFloat(v, 64); err != nil {
+			errs = errs.Also(apis.ErrInvalidValue(v, k))
+		} else if fv < TargetMin {
 			errs = errs.Also(apis.ErrGeneric(fmt.Sprintf("target %s should be at least %g", v, TargetMin), k))
 		}
 	}
@@ -242,8 +244,12 @@ func validateMetric(m map[string]string) *apis.FieldError {
 func validateInitialScale(config *autoscalerconfig.Config, m map[string]string) *apis.FieldError {
 	if k, v, ok := InitialScaleAnnotation.Get(m); ok {
 		initScaleInt, err := strconv.Atoi(v)
-		if err != nil || initScaleInt < 0 || (!config.AllowZeroInitialScale && initScaleInt == 0) {
+		if err != nil {
 			return apis.ErrInvalidValue(v, k)
+		} else if initScaleInt < 0 {
+			return apis.ErrInvalidValue(v, fmt.Sprintf("%s must be greater than 0", k))
+		} else if !config.AllowZeroInitialScale && initScaleInt == 0 {
+			return apis.ErrInvalidValue(v, fmt.Sprintf("%s=0 not allowed by cluster", k))
 		}
 	}
 	return nil
diff --git a/vendor/knative.dev/serving/pkg/apis/autoscaling/v1alpha1/zz_generated.deepcopy.go b/vendor/knative.dev/serving/pkg/apis/autoscaling/v1alpha1/zz_generated.deepcopy.go
index 5674ae01..5c328191 100644
--- a/vendor/knative.dev/serving/pkg/apis/autoscaling/v1alpha1/zz_generated.deepcopy.go
+++ b/vendor/knative.dev/serving/pkg/apis/autoscaling/v1alpha1/zz_generated.deepcopy.go
@@ -2,7 +2,7 @@
 // +build !ignore_autogenerated
 
 /*
-Copyright 2021 The Knative Authors
+Copyright 2022 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.
diff --git a/vendor/knative.dev/serving/pkg/apis/config/zz_generated.deepcopy.go b/vendor/knative.dev/serving/pkg/apis/config/zz_generated.deepcopy.go
index 13155bb0..dfd36f32 100644
--- a/vendor/knative.dev/serving/pkg/apis/config/zz_generated.deepcopy.go
+++ b/vendor/knative.dev/serving/pkg/apis/config/zz_generated.deepcopy.go
@@ -2,7 +2,7 @@
 // +build !ignore_autogenerated
 
 /*
-Copyright 2021 The Knative Authors
+Copyright 2022 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.
diff --git a/vendor/knative.dev/serving/pkg/apis/serving/k8s_validation.go b/vendor/knative.dev/serving/pkg/apis/serving/k8s_validation.go
index eeed43fc..f5a4728a 100644
--- a/vendor/knative.dev/serving/pkg/apis/serving/k8s_validation.go
+++ b/vendor/knative.dev/serving/pkg/apis/serving/k8s_validation.go
@@ -779,16 +779,16 @@ func validateProbe(p *corev1.Probe, port corev1.ContainerPort) *apis.FieldError
 		handlers = append(handlers, "httpGet")
 		errs = errs.Also(apis.CheckDisallowedFields(*h.HTTPGet, *HTTPGetActionMask(h.HTTPGet))).ViaField("httpGet")
 		getPort := h.HTTPGet.Port
-		if (getPort.StrVal != "" && getPort.StrVal != port.Name) || (getPort.IntVal != 0 && getPort.IntVal != port.ContainerPort) {
-			errs = errs.Also(apis.ErrInvalidValue(getPort.String(), "httpGet.port", "May only probe containerPort"))
+		if getPort.StrVal != "" && getPort.StrVal != port.Name {
+			errs = errs.Also(apis.ErrInvalidValue(getPort.String(), "httpGet.port", "Probe port must match container port"))
 		}
 	}
 	if h.TCPSocket != nil {
 		handlers = append(handlers, "tcpSocket")
 		errs = errs.Also(apis.CheckDisallowedFields(*h.TCPSocket, *TCPSocketActionMask(h.TCPSocket))).ViaField("tcpSocket")
 		tcpPort := h.TCPSocket.Port
-		if (tcpPort.StrVal != "" && tcpPort.StrVal != port.Name) || (tcpPort.IntVal != 0 && tcpPort.IntVal != port.ContainerPort) {
-			errs = errs.Also(apis.ErrInvalidValue(tcpPort.String(), "tcpSocket.port", "May only probe containerPort"))
+		if tcpPort.StrVal != "" && tcpPort.StrVal != port.Name {
+			errs = errs.Also(apis.ErrInvalidValue(tcpPort.String(), "tcpSocket.port", "Probe port must match container port"))
 		}
 	}
 	if h.Exec != nil {
diff --git a/vendor/knative.dev/serving/pkg/apis/serving/metadata_validation.go b/vendor/knative.dev/serving/pkg/apis/serving/metadata_validation.go
index e98d5c54..3f01b80c 100644
--- a/vendor/knative.dev/serving/pkg/apis/serving/metadata_validation.go
+++ b/vendor/knative.dev/serving/pkg/apis/serving/metadata_validation.go
@@ -89,7 +89,6 @@ func ValidateHasNoAutoscalingAnnotation(annotations map[string]string) (errs *ap
 }
 
 // ValidateContainerConcurrency function validates the ContainerConcurrency field
-// TODO(#5007): Move this to autoscaling.
 func ValidateContainerConcurrency(ctx context.Context, containerConcurrency *int64) *apis.FieldError {
 	if containerConcurrency != nil {
 		cfg := config.FromContextOrDefaults(ctx).Defaults
diff --git a/vendor/knative.dev/serving/pkg/apis/serving/v1/zz_generated.deepcopy.go b/vendor/knative.dev/serving/pkg/apis/serving/v1/zz_generated.deepcopy.go
index d249e4ff..99ae1ca1 100644
--- a/vendor/knative.dev/serving/pkg/apis/serving/v1/zz_generated.deepcopy.go
+++ b/vendor/knative.dev/serving/pkg/apis/serving/v1/zz_generated.deepcopy.go
@@ -2,7 +2,7 @@
 // +build !ignore_autogenerated
 
 /*
-Copyright 2021 The Knative Authors
+Copyright 2022 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.
diff --git a/vendor/knative.dev/serving/pkg/apis/serving/v1alpha1/zz_generated.deepcopy.go b/vendor/knative.dev/serving/pkg/apis/serving/v1alpha1/zz_generated.deepcopy.go
index 39c2d909..5b52d366 100644
--- a/vendor/knative.dev/serving/pkg/apis/serving/v1alpha1/zz_generated.deepcopy.go
+++ b/vendor/knative.dev/serving/pkg/apis/serving/v1alpha1/zz_generated.deepcopy.go
@@ -2,7 +2,7 @@
 // +build !ignore_autogenerated
 
 /*
-Copyright 2021 The Knative Authors
+Copyright 2022 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.
diff --git a/vendor/knative.dev/serving/pkg/apis/serving/v1beta1/zz_generated.deepcopy.go b/vendor/knative.dev/serving/pkg/apis/serving/v1beta1/zz_generated.deepcopy.go
index 956f3ddd..93949024 100644
--- a/vendor/knative.dev/serving/pkg/apis/serving/v1beta1/zz_generated.deepcopy.go
+++ b/vendor/knative.dev/serving/pkg/apis/serving/v1beta1/zz_generated.deepcopy.go
@@ -2,7 +2,7 @@
 // +build !ignore_autogenerated
 
 /*
-Copyright 2021 The Knative Authors
+Copyright 2022 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.
diff --git a/vendor/knative.dev/serving/pkg/autoscaler/config/autoscalerconfig/zz_generated.deepcopy.go b/vendor/knative.dev/serving/pkg/autoscaler/config/autoscalerconfig/zz_generated.deepcopy.go
index 45d989dc..5f2f2bf6 100644
--- a/vendor/knative.dev/serving/pkg/autoscaler/config/autoscalerconfig/zz_generated.deepcopy.go
+++ b/vendor/knative.dev/serving/pkg/autoscaler/config/autoscalerconfig/zz_generated.deepcopy.go
@@ -2,7 +2,7 @@
 // +build !ignore_autogenerated
 
 /*
-Copyright 2021 The Knative Authors
+Copyright 2022 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.
diff --git a/vendor/knative.dev/serving/pkg/client/clientset/versioned/scheme/doc.go b/vendor/knative.dev/serving/pkg/client/clientset/versioned/scheme/doc.go
index 5597166b..a9b21c5c 100644
--- a/vendor/knative.dev/serving/pkg/client/clientset/versioned/scheme/doc.go
+++ b/vendor/knative.dev/serving/pkg/client/clientset/versioned/scheme/doc.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2021 The Knative Authors
+Copyright 2022 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.
diff --git a/vendor/knative.dev/serving/pkg/client/clientset/versioned/scheme/register.go b/vendor/knative.dev/serving/pkg/client/clientset/versioned/scheme/register.go
index a00e59ac..bff6a218 100644
--- a/vendor/knative.dev/serving/pkg/client/clientset/versioned/scheme/register.go
+++ b/vendor/knative.dev/serving/pkg/client/clientset/versioned/scheme/register.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2021 The Knative Authors
+Copyright 2022 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.
diff --git a/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1/configuration.go b/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1/configuration.go
index 84268088..a229c824 100644
--- a/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1/configuration.go
+++ b/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1/configuration.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2021 The Knative Authors
+Copyright 2022 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.
diff --git a/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1/doc.go b/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1/doc.go
index 8c88ffc0..96a2eacb 100644
--- a/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1/doc.go
+++ b/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1/doc.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2021 The Knative Authors
+Copyright 2022 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.
diff --git a/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1/generated_expansion.go b/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1/generated_expansion.go
index e9fb4150..f974b447 100644
--- a/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1/generated_expansion.go
+++ b/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1/generated_expansion.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2021 The Knative Authors
+Copyright 2022 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.
diff --git a/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1/revision.go b/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1/revision.go
index ea57aa2a..fb3a2f39 100644
--- a/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1/revision.go
+++ b/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1/revision.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2021 The Knative Authors
+Copyright 2022 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.
diff --git a/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1/route.go b/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1/route.go
index 87bd2786..3e068449 100644
--- a/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1/route.go
+++ b/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1/route.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2021 The Knative Authors
+Copyright 2022 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.
diff --git a/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1/service.go b/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1/service.go
index ff25abea..7f2fc04e 100644
--- a/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1/service.go
+++ b/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1/service.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2021 The Knative Authors
+Copyright 2022 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.
diff --git a/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1/serving_client.go b/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1/serving_client.go
index c5d87358..1e82e5b7 100644
--- a/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1/serving_client.go
+++ b/vendor/knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1/serving_client.go
@@ -1,5 +1,5 @@
 /*
-Copyright 2021 The Knative Authors
+Copyright 2022 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.
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 16d81397..3c24cfd9 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -662,7 +662,7 @@ github.com/peterbourgon/diskv
 github.com/pkg/errors
 # github.com/pmezard/go-difflib v1.0.0
 github.com/pmezard/go-difflib/difflib
-# github.com/prometheus/client_golang v1.11.0
+# github.com/prometheus/client_golang v1.11.1
 github.com/prometheus/client_golang/prometheus
 github.com/prometheus/client_golang/prometheus/internal
 github.com/prometheus/client_golang/prometheus/promhttp
@@ -1320,7 +1320,7 @@ k8s.io/utils/buffer
 k8s.io/utils/integer
 k8s.io/utils/pointer
 k8s.io/utils/trace
-# knative.dev/client v0.29.0
+# knative.dev/client v0.30.1
 ## explicit
 knative.dev/client/pkg/config
 knative.dev/client/pkg/errors
@@ -1333,7 +1333,7 @@ knative.dev/client/pkg/serving/v1
 knative.dev/client/pkg/util
 knative.dev/client/pkg/util/mock
 knative.dev/client/pkg/wait
-# knative.dev/eventing v0.29.2-0.20220420140829-ce4fe0990d23
+# knative.dev/eventing v0.30.4-0.20220601140224-ec844245369e
 ## explicit
 knative.dev/eventing/pkg/apis/config
 knative.dev/eventing/pkg/apis/duck
@@ -1353,14 +1353,13 @@ knative.dev/eventing/pkg/apis/sources/v1
 knative.dev/eventing/pkg/apis/sources/v1beta2
 knative.dev/eventing/pkg/client/clientset/versioned/scheme
 knative.dev/eventing/pkg/client/clientset/versioned/typed/eventing/v1
-# knative.dev/hack v0.0.0-20220128200847-51a42b2eb63e
+# knative.dev/hack v0.0.0-20220629135030-82afbd367967
 ## explicit
 knative.dev/hack
-# knative.dev/networking v0.0.0-20220120045035-ec849677a316
-## explicit
+# knative.dev/networking v0.0.0-20220302134042-e8b2eb995165
 knative.dev/networking/pkg/apis/networking
 knative.dev/networking/pkg/apis/networking/v1alpha1
-# knative.dev/pkg v0.0.0-20220222214439-083dd97300e1
+# knative.dev/pkg v0.0.0-20220314165618-a637a96a1bd9
 ## explicit
 knative.dev/pkg/apis
 knative.dev/pkg/apis/duck
@@ -1392,7 +1391,7 @@ knative.dev/pkg/resolver
 knative.dev/pkg/signals
 knative.dev/pkg/system
 knative.dev/pkg/tracker
-# knative.dev/serving v0.29.5
+# knative.dev/serving v0.30.3-0.20220630163432-b5f775538f3d
 ## explicit
 knative.dev/serving/pkg/apis/autoscaling
 knative.dev/serving/pkg/apis/autoscaling/v1alpha1


Test patch:
diff --git a/client_int_test.go b/client_int_test.go
index 94c628fb..29d35541 100644
--- a/client_int_test.go
+++ b/client_int_test.go
@@ -205,7 +205,7 @@ func TestRemoteRepositories(t *testing.T) {
 func newClient(verbose bool) *fn.Client {
 	builder := buildpacks.NewBuilder(buildpacks.WithVerbose(verbose))
 	pusher := docker.NewPusher(docker.WithVerbose(verbose))
-	deployer := knative.NewDeployer(DefaultNamespace, verbose)
+	deployer := knative.NewDeployer(knative.WithDeployerNamespace(DefaultNamespace), knative.WithDeployerVerbose(verbose))
 	remover := knative.NewRemover(DefaultNamespace, verbose)
 	lister := knative.NewLister(DefaultNamespace, verbose)
 
diff --git a/cmd/deploy_test.go b/cmd/deploy_test.go
index 2b8c5fbc..445861da 100644
--- a/cmd/deploy_test.go
+++ b/cmd/deploy_test.go
@@ -2,6 +2,7 @@ package cmd
 
 import (
 	"context"
+	"fmt"
 	"os"
 	"testing"
 
@@ -180,3 +181,92 @@ created: 2009-11-10 23:00:00`,
 		})
 	}
 }
+
+func Test_imageWithDigest(t *testing.T) {
+	tests := []struct {
+		name      string
+		image     string
+		buildType string
+		pushBool  bool
+		funcFile  string
+		errString string
+	}{
+		{
+			name:      "valid full name with digest, expect success",
+			image:     "docker.io/4141gauron3268/static_test_digest:latest@sha256:7d66645b0add6de7af77ef332ecd4728649a2f03b9a2716422a054805b595c4e",
+			errString: "",
+			funcFile: `name: test-func
+runtime: go`,
+		},
+		{
+			name:      "valid image name, build not 'disabled', expect error",
+			image:     "docker.io/4141gauron3268/static_test_digest:latest@sha256:7d66645b0add6de7af77ef332ecd4728649a2f03b9a2716422a054805b595c4e",
+			buildType: "local",
+			errString: "the --build flag 'local' is not valid when using --image with digest",
+			funcFile: `name: test-func
+runtime: go`,
+		},
+		{
+			name:      "valid image name, --push specified, expect error",
+			image:     "docker.io/4141gauron3268/static_test_digest:latest@sha256:7d66645b0add6de7af77ef332ecd4728649a2f03b9a2716422a054805b595c4e",
+			pushBool:  true,
+			errString: "the --push flag 'true' is not valid when using --image with digest",
+			funcFile: `name: test-func
+runtime: go`,
+		},
+		{
+			name:      "invalid digest prefix, expect error",
+			image:     "docker.io/4141gauron3268/static_test_digest:latest@Xsha256:7d66645b0add6de7af77ef332ecd4728649a2f03b9a2716422a054805b595c4e",
+			errString: "value 'docker.io/4141gauron3268/static_test_digest:latest@Xsha256:7d66645b0add6de7af77ef332ecd4728649a2f03b9a2716422a054805b595c4e' in --image has invalid prefix syntax for digest (should be 'sha256:')",
+			funcFile: `name: test-func
+runtime: go`,
+		},
+		{
+			name:      "invalid sha hash length(added X at the end), expect error",
+			image:     "docker.io/4141gauron3268/static_test_digest:latest@sha256:7d66645b0add6de7af77ef332ecd4728649a2f03b9a2716422a054805b595c4eX",
+			errString: "sha256 hash in 'sha256:7d66645b0add6de7af77ef332ecd4728649a2f03b9a2716422a054805b595c4eX' from --image has the wrong length (65), should be 64",
+			funcFile: `name: test-func
+runtime: go`,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			deployer := mock.NewDeployer()
+			cmd := NewDeployCmd(NewClientFactory(func() *fn.Client {
+				return fn.New(
+					fn.WithDeployer(deployer))
+			}))
+
+			// Set flags manually & reset after.
+			// Differs whether build was set via CLI (gives an error if not 'disabled')
+			// or not (prints just a warning)
+			if tt.buildType == "" {
+				cmd.SetArgs([]string{
+					fmt.Sprintf("--image=%s", tt.image),
+					fmt.Sprintf("--push=%t", tt.pushBool),
+				})
+			} else {
+				cmd.SetArgs([]string{
+					fmt.Sprintf("--image=%s", tt.image),
+					fmt.Sprintf("--build=%s", tt.buildType),
+					fmt.Sprintf("--push=%t", tt.pushBool),
+				})
+			}
+			defer cmd.ResetFlags()
+
+			// set test case's func.yaml
+			if err := os.WriteFile("func.yaml", []byte(tt.funcFile), os.ModePerm); err != nil {
+				t.Fatal(err)
+			}
+
+			ctx := context.TODO()
+
+			_, err := cmd.ExecuteContextC(ctx)
+			if err != nil {
+				if err := err.Error(); tt.errString != err {
+					t.Fatalf("Error expected to be (%v) but was (%v)", tt.errString, err)
+				}
+			}
+		})
+	}
+}
diff --git a/docker/creds/credentials_test.go b/docker/creds/credentials_test.go
index a053cb6d..906fb345 100644
--- a/docker/creds/credentials_test.go
+++ b/docker/creds/credentials_test.go
@@ -154,7 +154,7 @@ func TestCheckAuth(t *testing.T) {
 				Username: tt.args.username,
 				Password: tt.args.password,
 			}
-			if err := creds.CheckAuth(tt.args.ctx, tt.args.registry, c, http.DefaultTransport); (err != nil) != tt.wantErr {
+			if err := creds.CheckAuth(tt.args.ctx, tt.args.registry+"/someorg/someimage:sometag", c, http.DefaultTransport); (err != nil) != tt.wantErr {
 				t.Errorf("CheckAuth() error = %v, wantErr %v", err, tt.wantErr)
 			}
 		})
@@ -165,7 +165,7 @@ func TestCheckAuthEmptyCreds(t *testing.T) {
 
 	localhost, _, stopServer := startServer(t, "", "")
 	t.Cleanup(stopServer)
-	err := creds.CheckAuth(context.Background(), localhost, docker.Credentials{}, http.DefaultTransport)
+	err := creds.CheckAuth(context.Background(), localhost+"/someorg/someimage:sometag", docker.Credentials{}, http.DefaultTransport)
 	if err != nil {
 		t.Error(err)
 	}
@@ -412,7 +412,7 @@ func TestNewCredentialsProvider(t *testing.T) {
 				creds.WithPromptForCredentials(tt.args.promptUser),
 				creds.WithVerifyCredentials(tt.args.verifyCredentials),
 				creds.WithAdditionalCredentialLoaders(tt.args.additionalLoaders...))
-			got, err := credentialsProvider(context.Background(), tt.args.registry)
+			got, err := credentialsProvider(context.Background(), tt.args.registry+"/someorg/someimage:sometag")
 			if err != nil {
 				t.Errorf("unexpected error: %v", err)
 				return
@@ -425,14 +425,14 @@ func TestNewCredentialsProvider(t *testing.T) {
 }
 
 func TestNewCredentialsProviderEmptyCreds(t *testing.T) {
-	credentialsProvider := creds.NewCredentialsProvider(creds.WithVerifyCredentials(func(ctx context.Context, registry string, credentials docker.Credentials) error {
-		if registry == "localhost:5000" && credentials == (docker.Credentials{}) {
+	credentialsProvider := creds.NewCredentialsProvider(creds.WithVerifyCredentials(func(ctx context.Context, image string, credentials docker.Credentials) error {
+		if image == "localhost:5555/someorg/someimage:sometag" && credentials == (docker.Credentials{}) {
 			return nil
 		}
 		t.Fatal("unreachable")
 		return nil
 	}))
-	c, err := credentialsProvider(context.Background(), "localhost:5000")
+	c, err := credentialsProvider(context.Background(), "localhost:5555/someorg/someimage:sometag")
 	if err != nil {
 		t.Error(err)
 	}
@@ -474,7 +474,7 @@ func TestCredentialsProviderSavingFromUserInput(t *testing.T) {
 		creds.WithPromptForCredentials(pwdCbk),
 		creds.WithVerifyCredentials(correctVerifyCbk),
 		creds.WithPromptForCredentialStore(chooseNoStore))
-	_, err := credentialsProvider(context.Background(), "docker.io")
+	_, err := credentialsProvider(context.Background(), "docker.io/someorg/someimage:sometag")
 	if err != nil {
 		t.Errorf("unexpected error: %v", err)
 		return
@@ -493,7 +493,7 @@ func TestCredentialsProviderSavingFromUserInput(t *testing.T) {
 		creds.WithPromptForCredentials(pwdCbk),
 		creds.WithVerifyCredentials(correctVerifyCbk),
 		creds.WithPromptForCredentialStore(chooseMockStore))
-	_, err = credentialsProvider(context.Background(), "docker.io")
+	_, err = credentialsProvider(context.Background(), "docker.io/someorg/someimage:sometag")
 	if err != nil {
 		t.Errorf("unexpected error: %v", err)
 		return
@@ -515,7 +515,7 @@ func TestCredentialsProviderSavingFromUserInput(t *testing.T) {
 		creds.WithPromptForCredentials(pwdCbkThatShallNotBeCalled(t)),
 		creds.WithVerifyCredentials(correctVerifyCbk),
 		creds.WithPromptForCredentialStore(shallNotBeInvoked))
-	_, err = credentialsProvider(context.Background(), "docker.io")
+	_, err = credentialsProvider(context.Background(), "docker.io/someorg/someimage:sometag")
 	if err != nil {
 		t.Errorf("unexpected error: %v", err)
 		return
@@ -609,7 +609,7 @@ func pwdCbkFirstWrongThenCorrect(t *testing.T) func(registry string) (Credential
 	t.Helper()
 	var firstInvocation bool
 	return func(registry string) (Credentials, error) {
-		if registry != "docker.io" && registry != "quay.io" {
+		if registry != "index.docker.io" && registry != "quay.io" {
 			return Credentials{}, fmt.Errorf("unexpected registry: %s", registry)
 		}
 		if firstInvocation {
@@ -621,7 +621,7 @@ func pwdCbkFirstWrongThenCorrect(t *testing.T) func(registry string) (Credential
 }
 
 func correctPwdCallback(registry string) (Credentials, error) {
-	if registry == "docker.io" {
+	if registry == "index.docker.io" {
 		return Credentials{Username: dockerIoUser, Password: dockerIoUserPwd}, nil
 	}
 	if registry == "quay.io" {
@@ -630,12 +630,12 @@ func correctPwdCallback(registry string) (Credentials, error) {
 	return Credentials{}, errors.New("this cbk don't know the pwd")
 }
 
-func correctVerifyCbk(ctx context.Context, registry string, credentials Credentials) error {
+func correctVerifyCbk(ctx context.Context, image string, credentials Credentials) error {
 	username, password := credentials.Username, credentials.Password
-	if username == dockerIoUser && password == dockerIoUserPwd && registry == "docker.io" {
+	if username == dockerIoUser && password == dockerIoUserPwd && image == "docker.io/someorg/someimage:sometag" {
 		return nil
 	}
-	if username == quayIoUser && password == quayIoUserPwd && registry == "quay.io" {
+	if username == quayIoUser && password == quayIoUserPwd && image == "quay.io/someorg/someimage:sometag" {
 		return nil
 	}
 	return creds.ErrUnauthorized
diff --git a/vendor/knative.dev/hack/presubmit-tests.sh b/vendor/knative.dev/hack/presubmit-tests.sh
index 08bd85d4..5f219d9a 100644
--- a/vendor/knative.dev/hack/presubmit-tests.sh
+++ b/vendor/knative.dev/hack/presubmit-tests.sh
@@ -23,7 +23,7 @@ source $(dirname "${BASH_SOURCE[0]}")/library.sh
 readonly PRESUBMIT_TEST_FAIL_FAST=${PRESUBMIT_TEST_FAIL_FAST:-0}
 
 # Extensions or file patterns that don't require presubmit tests.
-readonly NO_PRESUBMIT_FILES=(\.png \.gitignore \.gitattributes ^OWNERS ^OWNERS_ALIASES ^AUTHORS)
+readonly NO_PRESUBMIT_FILES=(\.png \.gitignore \.gitattributes ^OWNERS ^OWNERS_ALIASES ^AUTHORS \.github/.*)
 
 # Flag if this is a presubmit run or not.
 (( IS_PROW )) && [[ ${JOB_TYPE} == "presubmit" ]] && IS_PRESUBMIT=1 || IS_PRESUBMIT=0