Repository: GoogleContainerTools/skaffold
Pull request #8104 (2022-11-16 22:08:59)

docs: add link to Cloud Run YAML reference in deployer doc

**Description**
Add a direct link to the Cloud Run YAML reference in the Cloud Run deployer docs.

codecov[bot]: # [Codecov](https://codecov.io/gh/GoogleContainerTools/skaffold/pull/8104?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleContainerTools) Report
> Merging [#8104](https://codecov.io/gh/GoogleContainerTools/skaffold/pull/8104?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleContainerTools) (3a749ab) into [main](https://codecov.io/gh/GoogleContainerTools/skaffold/commit/290280e8c6c19231e9ed5b5c027f2c01d22f75be?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleContainerTools) (290280e) will **decrease** coverage by `4.06%`.
> The diff coverage is `53.26%`.

```diff
@@            Coverage Diff             @@
##             main    #8104      +/-   ##
==========================================
- Coverage   70.48%   66.41%   -4.07%     
==========================================
  Files         515      597      +82     
  Lines       23150    29177    +6027     
==========================================
+ Hits        16317    19378    +3061     
- Misses       5776     8349    +2573     
- Partials     1057     1450     +393     
```


| [Impacted Files](https://codecov.io/gh/GoogleContainerTools/skaffold/pull/8104?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleContainerTools) | Coverage Δ | |
|---|---|---|
| [cmd/skaffold/app/cmd/completion.go](https://codecov.io/gh/GoogleContainerTools/skaffold/pull/8104/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleContainerTools#diff-Y21kL3NrYWZmb2xkL2FwcC9jbWQvY29tcGxldGlvbi5nbw==) | `13.04% <0.00%> (-1.25%)` | :arrow_down: |
| [cmd/skaffold/app/cmd/credits/export.go](https://codecov.io/gh/GoogleContainerTools/skaffold/pull/8104/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleContainerTools#diff-Y21kL3NrYWZmb2xkL2FwcC9jbWQvY3JlZGl0cy9leHBvcnQuZ28=) | `0.00% <0.00%> (ø)` | |
| [cmd/skaffold/app/cmd/deploy.go](https://codecov.io/gh/GoogleContainerTools/skaffold/pull/8104/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleContainerTools#diff-Y21kL3NrYWZmb2xkL2FwcC9jbWQvZGVwbG95Lmdv) | `40.90% <0.00%> (-12.94%)` | :arrow_down: |
| [cmd/skaffold/app/cmd/test.go](https://codecov.io/gh/GoogleContainerTools/skaffold/pull/8104/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleContainerTools#diff-Y21kL3NrYWZmb2xkL2FwcC9jbWQvdGVzdC5nbw==) | `44.44% <0.00%> (ø)` | |
| [cmd/skaffold/app/exitcode.go](https://codecov.io/gh/GoogleContainerTools/skaffold/pull/8104/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleContainerTools#diff-Y21kL3NrYWZmb2xkL2FwcC9leGl0Y29kZS5nbw==) | `100.00% <ø> (+6.66%)` | :arrow_up: |
| [cmd/skaffold/skaffold.go](https://codecov.io/gh/GoogleContainerTools/skaffold/pull/8104/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleContainerTools#diff-Y21kL3NrYWZmb2xkL3NrYWZmb2xkLmdv) | `0.00% <0.00%> (ø)` | |
| [cmd/skaffold/app/cmd/inspect\_tests.go](https://codecov.io/gh/GoogleContainerTools/skaffold/pull/8104/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleContainerTools#diff-Y21kL3NrYWZmb2xkL2FwcC9jbWQvaW5zcGVjdF90ZXN0cy5nbw==) | `62.50% <14.28%> (-1.14%)` | :arrow_down: |
| [cmd/skaffold/app/cmd/render.go](https://codecov.io/gh/GoogleContainerTools/skaffold/pull/8104/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleContainerTools#diff-Y21kL3NrYWZmb2xkL2FwcC9jbWQvcmVuZGVyLmdv) | `35.48% <18.18%> (-5.90%)` | :arrow_down: |
| [cmd/skaffold/app/cmd/lsp.go](https://codecov.io/gh/GoogleContainerTools/skaffold/pull/8104/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleContainerTools#diff-Y21kL3NrYWZmb2xkL2FwcC9jbWQvbHNwLmdv) | `28.12% <28.12%> (ø)` | |
| [cmd/skaffold/app/cmd/run.go](https://codecov.io/gh/GoogleContainerTools/skaffold/pull/8104/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleContainerTools#diff-Y21kL3NrYWZmb2xkL2FwcC9jbWQvcnVuLmdv) | `64.28% <33.33%> (-9.63%)` | :arrow_down: |
| ... and [394 more](https://codecov.io/gh/GoogleContainerTools/skaffold/pull/8104/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleContainerTools) | |

:mega: We’re building smart automated test selection to slash your CI/CD build times. [Learn more](https://about.codecov.io/iterative-testing/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleContainerTools)


Patch:
diff --git a/deploy/skaffold/Dockerfile.deps b/deploy/skaffold/Dockerfile.deps
index e4448175d..09322b35e 100644
--- a/deploy/skaffold/Dockerfile.deps
+++ b/deploy/skaffold/Dockerfile.deps
@@ -151,7 +151,7 @@ RUN apt-get update && apt-get install --no-install-recommends --no-install-sugge
     build-essential \
     python-setuptools \
     lsb-release \
-    openjdk-11-jdk \
+    openjdk-17-jdk \
     software-properties-common \
     jq \
     apt-transport-https && \
diff --git a/deploy/skaffold/Dockerfile.deps.lts b/deploy/skaffold/Dockerfile.deps.lts
index cbd7d4ea4..ee40c65a7 100644
--- a/deploy/skaffold/Dockerfile.deps.lts
+++ b/deploy/skaffold/Dockerfile.deps.lts
@@ -95,7 +95,7 @@ RUN apt-get update && apt-get install --no-install-recommends --no-install-sugge
     build-essential \
     python-setuptools \
     lsb-release \
-    openjdk-11-jdk \
+    openjdk-17-jdk \
     software-properties-common \
     jq \
     apt-transport-https && \
diff --git a/deploy/skaffold/Dockerfile.deps.slim b/deploy/skaffold/Dockerfile.deps.slim
index cbd7d4ea4..ee40c65a7 100644
--- a/deploy/skaffold/Dockerfile.deps.slim
+++ b/deploy/skaffold/Dockerfile.deps.slim
@@ -95,7 +95,7 @@ RUN apt-get update && apt-get install --no-install-recommends --no-install-sugge
     build-essential \
     python-setuptools \
     lsb-release \
-    openjdk-11-jdk \
+    openjdk-17-jdk \
     software-properties-common \
     jq \
     apt-transport-https && \
diff --git a/docs-v2/content/en/docs/pipeline-stages/deployers/cloudrun.md b/docs-v2/content/en/docs/pipeline-stages/deployers/cloudrun.md
index e6f8e0976..13d791a81 100644
--- a/docs-v2/content/en/docs/pipeline-stages/deployers/cloudrun.md
+++ b/docs-v2/content/en/docs/pipeline-stages/deployers/cloudrun.md
@@ -15,6 +15,7 @@ Cloud Run is a managed compute platform on Google Cloud that allows you to run c
 ## Deploying applications to Cloud Run
 
 Skaffold can deploy services to Cloud Run. If this deployer is used, all provided manifests must be valid Cloud Run services, using the serving.knative.dev/v1 schema.
+See the [Cloud Run YAML reference](https://cloud.google.com/run/docs/reference/yaml/v1) for supported fields.
 
 This deployer will use the [application default credentials](https://cloud.google.com/docs/authentication/production#automatically) to deploy.  You can configure this to use your user credentials by running `gcloud auth application-default login`.
 
@@ -37,4 +38,4 @@ artifacts to Cloud Run:
 Images listed to be deployed with the Cloud Run deployer must be present in Google Artifact
 Registry or Google Container Registry. If you are using Skaffold to build the images, ensure `push` is 
 set to true.
-{{< /alert >}}
\ No newline at end of file
+{{< /alert >}}
diff --git a/examples/bazel/skaffold.yaml b/examples/bazel/skaffold.yaml
index 1a8e92672..6de5da1d0 100644
--- a/examples/bazel/skaffold.yaml
+++ b/examples/bazel/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 build:
   artifacts:
diff --git a/examples/buildpacks-java/skaffold.yaml b/examples/buildpacks-java/skaffold.yaml
index cb115cbd7..799b8dea7 100644
--- a/examples/buildpacks-java/skaffold.yaml
+++ b/examples/buildpacks-java/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 build:
   artifacts:
diff --git a/examples/buildpacks-node/skaffold.yaml b/examples/buildpacks-node/skaffold.yaml
index 9b4dc7e01..1b5bfdc24 100644
--- a/examples/buildpacks-node/skaffold.yaml
+++ b/examples/buildpacks-node/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 build:
   artifacts:
diff --git a/examples/buildpacks-python/skaffold.yaml b/examples/buildpacks-python/skaffold.yaml
index 00cbad0e2..3389161f9 100644
--- a/examples/buildpacks-python/skaffold.yaml
+++ b/examples/buildpacks-python/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 build:
   artifacts:
diff --git a/examples/buildpacks/skaffold.yaml b/examples/buildpacks/skaffold.yaml
index 1e1460dd5..7a1dff63b 100644
--- a/examples/buildpacks/skaffold.yaml
+++ b/examples/buildpacks/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 build:
   artifacts:
diff --git a/examples/cross-platform-builds/skaffold.yaml b/examples/cross-platform-builds/skaffold.yaml
index 5c866f824..8734e0f8b 100644
--- a/examples/cross-platform-builds/skaffold.yaml
+++ b/examples/cross-platform-builds/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 build:
   artifacts:
diff --git a/examples/custom-buildx/skaffold.yaml b/examples/custom-buildx/skaffold.yaml
index 5b6ce230b..fc1468424 100644
--- a/examples/custom-buildx/skaffold.yaml
+++ b/examples/custom-buildx/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3alpha1
+apiVersion: skaffold/v4beta1
 kind: Config
 build:
   platforms: ["linux/amd64", "linux/arm64"]
diff --git a/examples/custom/skaffold.yaml b/examples/custom/skaffold.yaml
index 4603b4913..3c412806d 100644
--- a/examples/custom/skaffold.yaml
+++ b/examples/custom/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 build:
   artifacts:
diff --git a/examples/dev-journey-buildpacks/skaffold.yaml b/examples/dev-journey-buildpacks/skaffold.yaml
index c4079a815..392ff1edf 100644
--- a/examples/dev-journey-buildpacks/skaffold.yaml
+++ b/examples/dev-journey-buildpacks/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 build:
   artifacts:
diff --git a/examples/docker-deploy/skaffold.yaml b/examples/docker-deploy/skaffold.yaml
index ba6dd2a59..a26cf99a4 100644
--- a/examples/docker-deploy/skaffold.yaml
+++ b/examples/docker-deploy/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 build:
   local:
diff --git a/examples/gcb-kaniko/skaffold.yaml b/examples/gcb-kaniko/skaffold.yaml
index cd34896ee..7ec7712ee 100644
--- a/examples/gcb-kaniko/skaffold.yaml
+++ b/examples/gcb-kaniko/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 build:
   googleCloudBuild:
diff --git a/examples/generate-pipeline/skaffold.yaml b/examples/generate-pipeline/skaffold.yaml
index 66c30cbdd..71362b72f 100644
--- a/examples/generate-pipeline/skaffold.yaml
+++ b/examples/generate-pipeline/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 build:
   artifacts:
diff --git a/examples/getting-started-kustomize/skaffold.yaml b/examples/getting-started-kustomize/skaffold.yaml
index b25b514ef..bdf689add 100644
--- a/examples/getting-started-kustomize/skaffold.yaml
+++ b/examples/getting-started-kustomize/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 metadata:
   name: getting-started-kustomize
diff --git a/examples/getting-started/skaffold.yaml b/examples/getting-started/skaffold.yaml
index 3d30914b3..8d176cf81 100644
--- a/examples/getting-started/skaffold.yaml
+++ b/examples/getting-started/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 build:
   artifacts:
diff --git a/examples/google-cloud-build/skaffold.yaml b/examples/google-cloud-build/skaffold.yaml
index 180cf56d6..59f9df8c4 100644
--- a/examples/google-cloud-build/skaffold.yaml
+++ b/examples/google-cloud-build/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 build:
   googleCloudBuild:
diff --git a/examples/helm-deployment-dependencies/skaffold.yaml b/examples/helm-deployment-dependencies/skaffold.yaml
index ef6d9e3f9..760b58cea 100644
--- a/examples/helm-deployment-dependencies/skaffold.yaml
+++ b/examples/helm-deployment-dependencies/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 build:
   tagPolicy:
diff --git a/examples/helm-deployment/skaffold.yaml b/examples/helm-deployment/skaffold.yaml
index a0cda4add..e4d8ee327 100644
--- a/examples/helm-deployment/skaffold.yaml
+++ b/examples/helm-deployment/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 build:
   artifacts:
diff --git a/examples/helm-remote-repo/skaffold.yaml b/examples/helm-remote-repo/skaffold.yaml
index 903ccd590..b37f1e8f2 100644
--- a/examples/helm-remote-repo/skaffold.yaml
+++ b/examples/helm-remote-repo/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 deploy:
   helm:
diff --git a/examples/helm-render/skaffold.yaml b/examples/helm-render/skaffold.yaml
index 9d99949d2..9edb3b5bf 100644
--- a/examples/helm-render/skaffold.yaml
+++ b/examples/helm-render/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 build:
   artifacts:
diff --git a/examples/hot-reload/skaffold.yaml b/examples/hot-reload/skaffold.yaml
index 49cf8331a..d62e05205 100644
--- a/examples/hot-reload/skaffold.yaml
+++ b/examples/hot-reload/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 build:
   artifacts:
diff --git a/examples/jib-gradle/skaffold.yaml b/examples/jib-gradle/skaffold.yaml
index 1d820fd94..4d2c0b7fa 100644
--- a/examples/jib-gradle/skaffold.yaml
+++ b/examples/jib-gradle/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 build:
   artifacts:
diff --git a/examples/jib-multimodule/skaffold.yaml b/examples/jib-multimodule/skaffold.yaml
index c4818a532..1f83b06f3 100644
--- a/examples/jib-multimodule/skaffold.yaml
+++ b/examples/jib-multimodule/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 build:
   artifacts:
diff --git a/examples/jib-sync/skaffold-gradle.yaml b/examples/jib-sync/skaffold-gradle.yaml
index fd29a5118..448024005 100644
--- a/examples/jib-sync/skaffold-gradle.yaml
+++ b/examples/jib-sync/skaffold-gradle.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 build:
   artifacts:
diff --git a/examples/jib-sync/skaffold-maven.yaml b/examples/jib-sync/skaffold-maven.yaml
index 4fb33df59..3eef86c1a 100644
--- a/examples/jib-sync/skaffold-maven.yaml
+++ b/examples/jib-sync/skaffold-maven.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 build:
   artifacts:
diff --git a/examples/jib/skaffold.yaml b/examples/jib/skaffold.yaml
index a622df80f..a4eb39e93 100644
--- a/examples/jib/skaffold.yaml
+++ b/examples/jib/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 build:
   artifacts:
diff --git a/examples/kaniko/skaffold.yaml b/examples/kaniko/skaffold.yaml
index 076b6aa88..bba3648af 100644
--- a/examples/kaniko/skaffold.yaml
+++ b/examples/kaniko/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 build:
   artifacts:
diff --git a/examples/ko-sync-infer/skaffold.yaml b/examples/ko-sync-infer/skaffold.yaml
index aea40621e..b8d465aeb 100644
--- a/examples/ko-sync-infer/skaffold.yaml
+++ b/examples/ko-sync-infer/skaffold.yaml
@@ -12,7 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 build:
   artifacts:
diff --git a/examples/ko/skaffold.yaml b/examples/ko/skaffold.yaml
index 646cc7911..826187cdf 100644
--- a/examples/ko/skaffold.yaml
+++ b/examples/ko/skaffold.yaml
@@ -12,7 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 build:
   artifacts:
diff --git a/examples/kustomize/skaffold-kustomize-args.yaml b/examples/kustomize/skaffold-kustomize-args.yaml
index 8a7e696f3..aece1007a 100644
--- a/examples/kustomize/skaffold-kustomize-args.yaml
+++ b/examples/kustomize/skaffold-kustomize-args.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 deploy:
   kustomize:
diff --git a/examples/kustomize/skaffold.yaml b/examples/kustomize/skaffold.yaml
index a7c2b2e36..7a8f5310f 100644
--- a/examples/kustomize/skaffold.yaml
+++ b/examples/kustomize/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 manifests:
   kustomize:
diff --git a/examples/lifecycle-hooks/skaffold.yaml b/examples/lifecycle-hooks/skaffold.yaml
index 59fc39792..8826595a9 100644
--- a/examples/lifecycle-hooks/skaffold.yaml
+++ b/examples/lifecycle-hooks/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 manifests:
   rawYaml:
diff --git a/examples/microservices/skaffold.yaml b/examples/microservices/skaffold.yaml
index 950c1006e..7decb4fe8 100644
--- a/examples/microservices/skaffold.yaml
+++ b/examples/microservices/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 build:
   artifacts:
diff --git a/examples/multi-config-microservices/base/skaffold.yaml b/examples/multi-config-microservices/base/skaffold.yaml
index 95fdea9c9..21fba868e 100644
--- a/examples/multi-config-microservices/base/skaffold.yaml
+++ b/examples/multi-config-microservices/base/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 build:
   artifacts:
diff --git a/examples/multi-config-microservices/leeroy-app/skaffold.yaml b/examples/multi-config-microservices/leeroy-app/skaffold.yaml
index ab67f4f12..bc36907f4 100644
--- a/examples/multi-config-microservices/leeroy-app/skaffold.yaml
+++ b/examples/multi-config-microservices/leeroy-app/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 metadata:
   name: app-config
diff --git a/examples/multi-config-microservices/leeroy-web/skaffold.yaml b/examples/multi-config-microservices/leeroy-web/skaffold.yaml
index bcadcdd2c..8f99a5891 100644
--- a/examples/multi-config-microservices/leeroy-web/skaffold.yaml
+++ b/examples/multi-config-microservices/leeroy-web/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 metadata:
   name: web-config
diff --git a/examples/multi-config-microservices/skaffold.yaml b/examples/multi-config-microservices/skaffold.yaml
index 7190ba6de..db4776baf 100644
--- a/examples/multi-config-microservices/skaffold.yaml
+++ b/examples/multi-config-microservices/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 requires:
 - path: ./leeroy-app
diff --git a/examples/multiple-renderers/skaffold.yaml b/examples/multiple-renderers/skaffold.yaml
index 38927c3d8..6a9581ecd 100644
--- a/examples/multiple-renderers/skaffold.yaml
+++ b/examples/multiple-renderers/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 metadata:
   name: go-guestbook
diff --git a/examples/nodejs/skaffold.yaml b/examples/nodejs/skaffold.yaml
index 3220b475a..adfc179d3 100644
--- a/examples/nodejs/skaffold.yaml
+++ b/examples/nodejs/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 
 build:
diff --git a/examples/profile-patches/skaffold.yaml b/examples/profile-patches/skaffold.yaml
index 4604fa59e..750cb1f8e 100644
--- a/examples/profile-patches/skaffold.yaml
+++ b/examples/profile-patches/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 build:
   # only build and deploy "base-service" on main profile
diff --git a/examples/profiles/skaffold.yaml b/examples/profiles/skaffold.yaml
index ecc530fd9..ba8e5b16d 100644
--- a/examples/profiles/skaffold.yaml
+++ b/examples/profiles/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 build:
   # only build and deploy "world-service" on main profile
diff --git a/examples/react-reload-docker/skaffold.yaml b/examples/react-reload-docker/skaffold.yaml
index 4cf90a3d1..de1c1941d 100644
--- a/examples/react-reload-docker/skaffold.yaml
+++ b/examples/react-reload-docker/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 build:
   local:
diff --git a/examples/react-reload/skaffold.yaml b/examples/react-reload/skaffold.yaml
index 73bfe1826..cd97a1aa1 100644
--- a/examples/react-reload/skaffold.yaml
+++ b/examples/react-reload/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 build:
   artifacts:
diff --git a/examples/remote-multi-config-microservices/skaffold.yaml b/examples/remote-multi-config-microservices/skaffold.yaml
index 64541a923..9e77b69fe 100644
--- a/examples/remote-multi-config-microservices/skaffold.yaml
+++ b/examples/remote-multi-config-microservices/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 requires:
 - git:
diff --git a/examples/ruby/skaffold.yaml b/examples/ruby/skaffold.yaml
index 6f57a9540..70c39eb5d 100644
--- a/examples/ruby/skaffold.yaml
+++ b/examples/ruby/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 build:
   artifacts:
diff --git a/examples/simple-artifact-dependency/skaffold.yaml b/examples/simple-artifact-dependency/skaffold.yaml
index 7af08b0a8..ac150b80a 100644
--- a/examples/simple-artifact-dependency/skaffold.yaml
+++ b/examples/simple-artifact-dependency/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 build:
   artifacts:
diff --git a/examples/tagging-with-environment-variables/skaffold.yaml b/examples/tagging-with-environment-variables/skaffold.yaml
index 4ceafd6c2..35550f900 100644
--- a/examples/tagging-with-environment-variables/skaffold.yaml
+++ b/examples/tagging-with-environment-variables/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 build:
   artifacts:
diff --git a/examples/templated-fields/skaffold.yaml b/examples/templated-fields/skaffold.yaml
index 1fa18ec1a..260255990 100644
--- a/examples/templated-fields/skaffold.yaml
+++ b/examples/templated-fields/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 metadata:
   name: my-app
diff --git a/examples/typescript/skaffold.yaml b/examples/typescript/skaffold.yaml
index 6317caf1a..235e8dd79 100644
--- a/examples/typescript/skaffold.yaml
+++ b/examples/typescript/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 
 build:
diff --git a/pkg/skaffold/deploy/cloudrun/deploy.go b/pkg/skaffold/deploy/cloudrun/deploy.go
index f1fb48e8c..ae3a23d35 100644
--- a/pkg/skaffold/deploy/cloudrun/deploy.go
+++ b/pkg/skaffold/deploy/cloudrun/deploy.go
@@ -49,12 +49,13 @@ type Config interface {
 	PortForwardResources() []*latest.PortForwardResource
 	PortForwardOptions() config.PortForwardOptions
 	Mode() config.RunMode
+	Tail() bool
 }
 
 // Deployer deploys code to Google Cloud Run.
 type Deployer struct {
 	configName string
-	logger     log.Logger
+	logger     *LogAggregator
 	accessor   *RunAccessor
 	monitor    *Monitor
 	labeller   *label.DefaultLabeller
@@ -74,7 +75,7 @@ func NewDeployer(cfg Config, labeller *label.DefaultLabeller, crDeploy *latest.C
 		Project:    crDeploy.ProjectID,
 		Region:     crDeploy.Region,
 		// TODO: implement logger for Cloud Run.
-		logger:        &log.NoopLogger{},
+		logger:        NewLoggerAggregator(cfg, labeller.GetRunID()),
 		accessor:      NewAccessor(cfg, labeller.GetRunID()),
 		labeller:      labeller,
 		useGcpOptions: true,
@@ -233,6 +234,7 @@ func (d *Deployer) deployService(crclient *run.APIService, manifest []byte, out
 	parent := fmt.Sprintf("projects/%s/locations/%s", service.Metadata.Namespace, d.Region)
 
 	sName := resName.String()
+	d.logger.AddResource(resName)
 	getCall := crclient.Projects.Locations.Services.Get(sName)
 	_, err := getCall.Do()
 
diff --git a/pkg/skaffold/deploy/cloudrun/formatter.go b/pkg/skaffold/deploy/cloudrun/formatter.go
new file mode 100644
index 000000000..037dff881
--- /dev/null
+++ b/pkg/skaffold/deploy/cloudrun/formatter.go
@@ -0,0 +1,39 @@
+/*
+Copyright 2022 The Skaffold 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 cloudrun
+
+import (
+	"io"
+
+	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/output"
+)
+
+type LogFormatter struct {
+	prefix      string
+	outputColor output.Color
+}
+
+func (formatter *LogFormatter) Name() string {
+	return formatter.prefix
+}
+func (formatter *LogFormatter) PrintLine(out io.Writer, line string) {
+	if output.IsColorable(out) {
+		formatter.outputColor.Fprintf(out, "[%s] %s", formatter.prefix, line)
+	} else {
+		output.Default.Fprintf(out, "[%s] %s", formatter.prefix, line)
+	}
+}
diff --git a/pkg/skaffold/deploy/cloudrun/log.go b/pkg/skaffold/deploy/cloudrun/log.go
new file mode 100644
index 000000000..686bf78a7
--- /dev/null
+++ b/pkg/skaffold/deploy/cloudrun/log.go
@@ -0,0 +1,223 @@
+/*
+Copyright 2022 The Skaffold 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 cloudrun
+
+import (
+	"bufio"
+	"context"
+	"fmt"
+	"io"
+	"os"
+	"os/exec"
+	"sync/atomic"
+	"time"
+
+	"golang.org/x/sync/singleflight"
+
+	sErrors "github.com/GoogleContainerTools/skaffold/pkg/skaffold/errors"
+	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/graph"
+	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/output"
+	"github.com/GoogleContainerTools/skaffold/proto/v1"
+)
+
+type logTailer interface {
+	Start(ctx context.Context, out io.Writer) error
+	Stop()
+}
+
+type logTailerResource struct {
+	name      RunResourceName
+	cancel    context.CancelFunc
+	isTailing bool
+	cmd       *exec.Cmd
+	formatter LogFormatter
+}
+
+type loggerTracker struct {
+	resources map[RunResourceName]*logTailerResource
+}
+
+type LogAggregator struct {
+	singleRun     singleflight.Group
+	resources     *loggerTracker
+	logTailers    []logTailer
+	muted         int32
+	label         string
+	serviceColors map[string]output.Color
+}
+
+func (r *LogAggregator) Mute() {
+	if r == nil {
+		// Logs are not activated.
+		return
+	}
+
+	atomic.StoreInt32(&r.muted, 1)
+}
+
+func (r *LogAggregator) Unmute() {
+	if r == nil {
+		// Logs are not activated.
+		return
+	}
+
+	atomic.StoreInt32(&r.muted, 0)
+}
+
+func (r *LogAggregator) SetSince(time time.Time) {
+}
+
+func (r *LogAggregator) RegisterArtifacts(artifacts []graph.Artifact) {
+}
+
+func NewLoggerAggregator(cfg Config, label string) *LogAggregator {
+	var logTailers []logTailer
+	resources := &loggerTracker{}
+	if cfg.Tail() {
+		logTailers = append(logTailers, &runLogTailer{resources: resources})
+	}
+	a := &LogAggregator{logTailers: logTailers, resources: resources, label: label, singleRun: singleflight.Group{}, serviceColors: make(map[string]output.Color)}
+	return a
+}
+
+func (r *LogAggregator) AddResource(resource RunResourceName) {
+	if r.resources.resources == nil {
+		r.resources.resources = make(map[RunResourceName]*logTailerResource)
+	}
+	if _, present := r.resources.resources[resource]; !present {
+		r.addServiceColor(resource.Service)
+		r.resources.resources[resource] = &logTailerResource{name: resource, formatter: LogFormatter{resource.Service, r.serviceColors[resource.Service]}}
+	} else {
+		r.resources.resources[resource].isTailing = true
+	}
+}
+
+func (r *LogAggregator) addServiceColor(serviceName string) {
+	if _, present := r.serviceColors[serviceName]; !present {
+		r.serviceColors[serviceName] = output.DefaultColorCodes[(len(r.serviceColors))&len(output.DefaultColorCodes)]
+	}
+}
+
+func (r *LogAggregator) Start(ctx context.Context, out io.Writer) error {
+	if r == nil {
+		return nil
+	}
+	_, err, _ := r.singleRun.Do(r.label, func() (interface{}, error) {
+		return struct{}{}, r.start(ctx, out)
+	})
+	return err
+}
+
+func (r *LogAggregator) start(ctx context.Context, out io.Writer) error {
+	for _, logTail := range r.logTailers {
+		if err := logTail.Start(ctx, out); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func (r *LogAggregator) Stop() {
+	for _, logTailer := range r.logTailers {
+		logTailer.Stop()
+	}
+}
+
+type runLogTailer struct {
+	resources *loggerTracker
+}
+
+func (r *runLogTailer) Start(ctx context.Context, out io.Writer) error {
+	if !gcloudInstalled() {
+		output.Red.Fprintln(out, "gcloud not found on path. Unable to set up Cloud Run port forwarding")
+		return sErrors.NewError(fmt.Errorf("gcloud not found"), &proto.ActionableErr{ErrCode: proto.StatusCode_LOG_STREAMING_RUN_GCLOUD_NOT_FOUND})
+	}
+	if r.resources.resources == nil {
+		return nil
+	}
+	go func() {
+		for _, resource := range r.resources.resources {
+			if !resource.isTailing {
+				cctx, cancel := context.WithCancel(ctx)
+				cmd := exec.CommandContext(cctx, "gcloud", getGcloudTailArgs(resource.name)...)
+				cmd.Env = os.Environ()
+				// gcloud uses buffered stream by default
+				cmd.Env = append(cmd.Env, "PYTHONUNBUFFERED=1") // gcloud defaults streaming output as buffered
+				r, w := io.Pipe()
+				cmd.Stderr = w
+				cmd.Stdout = w
+				resource.cancel = cancel
+				if err := cmd.Start(); err != nil {
+					output.Red.Fprintf(out, "failed to start log streaming on service %s\n", resource.name.Service)
+				}
+				if err := streamLog(ctx, out, r, resource.formatter); err != nil {
+					output.Red.Fprintf(out, "log streaming failed: %s\n", err)
+				}
+				go func() {
+					if err := cmd.Wait(); err != nil {
+						output.Red.Fprintf(out, "terminated\n")
+					}
+				}()
+				resource.isTailing = true
+				resource.cmd = cmd
+			}
+		}
+	}()
+	return nil
+}
+
+func streamLog(ctx context.Context, out io.Writer, rc io.Reader, formatter LogFormatter) error {
+	reader := bufio.NewReader(rc)
+	for {
+		select {
+		case <-ctx.Done():
+			output.Yellow.Fprintln(out, "log streaming was interrupted")
+			return nil
+		default:
+			line, err := reader.ReadString('\n')
+			if err == io.EOF {
+				return nil
+			}
+			if err != nil {
+				output.Red.Fprintf(out, "error reading bytes form log streaming: %v", err)
+				return err
+			}
+			formatter.PrintLine(out, line)
+		}
+	}
+}
+
+func (r *runLogTailer) Stop() {
+	for _, resource := range r.resources.resources {
+		if resource.cancel != nil {
+			if resource.cmd != nil {
+				if err := resource.cmd.Process.Signal(os.Interrupt); err != nil {
+					// signaling didn't work, force cancel
+					resource.cancel()
+				}
+			} else {
+				resource.cancel()
+			}
+			resource.cancel = nil
+			resource.cmd = nil
+		}
+	}
+}
+
+func getGcloudTailArgs(resource RunResourceName) []string {
+	return []string{"alpha", "run", "services", "logs", "tail", resource.Service, "--project", resource.Project, "--region", resource.Region}
+}
diff --git a/proto/enums/enums.pb.go b/proto/enums/enums.pb.go
index 3e7fa4f8a..858662ffb 100644
--- a/proto/enums/enums.pb.go
+++ b/proto/enums/enums.pb.go
@@ -886,6 +886,7 @@ const (
 	StatusCode_INSPECT_PROFILE_NOT_FOUND_ERR      StatusCode = 1304
 	StatusCode_PORT_FORWARD_RUN_GCLOUD_NOT_FOUND  StatusCode = 1601
 	StatusCode_PORT_FORWARD_RUN_PROXY_START_ERROR StatusCode = 1602
+	StatusCode_LOG_STREAM_RUN_GCLOUD_NOT_FOUND    StatusCode = 1603
 )
 
 // Enum value maps for StatusCode.
diff --git a/proto/v1/skaffold.pb.go b/proto/v1/skaffold.pb.go
index 5f54fbf6b..5a9d7ba7f 100644
--- a/proto/v1/skaffold.pb.go
+++ b/proto/v1/skaffold.pb.go
@@ -307,6 +307,7 @@ const StatusCode_INSPECT_BUILD_ENV_INCORRECT_TYPE_ERR = enums.StatusCode_INSPECT
 const StatusCode_INSPECT_PROFILE_NOT_FOUND_ERR = enums.StatusCode_INSPECT_PROFILE_NOT_FOUND_ERR
 const StatusCode_PORT_FORWARD_RUN_GCLOUD_NOT_FOUND = enums.StatusCode_PORT_FORWARD_RUN_GCLOUD_NOT_FOUND
 const StatusCode_PORT_FORWARD_RUN_PROXY_START_ERROR = enums.StatusCode_PORT_FORWARD_RUN_PROXY_START_ERROR
+const StatusCode_LOG_STREAMING_RUN_GCLOUD_NOT_FOUND = enums.StatusCode_LOG_STREAM_RUN_GCLOUD_NOT_FOUND
 
 var StatusCode_name = enums.StatusCode_name
 var StatusCode_value = enums.StatusCode_value


Test patch:
diff --git a/examples/custom-tests/skaffold.yaml b/examples/custom-tests/skaffold.yaml
index b8ca98003..fc4be9bfb 100644
--- a/examples/custom-tests/skaffold.yaml
+++ b/examples/custom-tests/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 build:
   artifacts:
diff --git a/examples/grpc-e2e-tests/skaffold.yaml b/examples/grpc-e2e-tests/skaffold.yaml
index 198be875e..8bd59dcb0 100644
--- a/examples/grpc-e2e-tests/skaffold.yaml
+++ b/examples/grpc-e2e-tests/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 metadata:
   name: visitor-counter-e2e
diff --git a/examples/structure-tests/skaffold.yaml b/examples/structure-tests/skaffold.yaml
index 6da269ce4..3cba01924 100644
--- a/examples/structure-tests/skaffold.yaml
+++ b/examples/structure-tests/skaffold.yaml
@@ -1,4 +1,4 @@
-apiVersion: skaffold/v3
+apiVersion: skaffold/v4beta1
 kind: Config
 build:
   artifacts:
diff --git a/pkg/skaffold/deploy/cloudrun/accessor_test.go b/pkg/skaffold/deploy/cloudrun/accessor_test.go
index f007fbf7e..6719130b8 100644
--- a/pkg/skaffold/deploy/cloudrun/accessor_test.go
+++ b/pkg/skaffold/deploy/cloudrun/accessor_test.go
@@ -39,6 +39,9 @@ func (t *testAccessConfig) PortForwardOptions() config.PortForwardOptions {
 func (t *testAccessConfig) Mode() config.RunMode {
 	return config.RunModes.Run
 }
+func (t *testAccessConfig) Tail() bool {
+	return true
+}
 func (t *testAccessConfig) PortForwardResources() []*latest.PortForwardResource {
 	return t.forwards
 }
@@ -232,6 +235,7 @@ func TestGcloudFoundServicesForwarder(t *testing.T) {
 			var b bytes.Buffer
 			writer := bufio.NewWriter(&b)
 			err := forwarder.Start(ctx, writer)
+			writer.Flush()
 			output := b.Bytes()
 			if test.expectStatus == proto.StatusCode_OK {
 				if err != nil {
diff --git a/pkg/skaffold/deploy/cloudrun/formatter_test.go b/pkg/skaffold/deploy/cloudrun/formatter_test.go
new file mode 100644
index 000000000..aea95dce9
--- /dev/null
+++ b/pkg/skaffold/deploy/cloudrun/formatter_test.go
@@ -0,0 +1,49 @@
+/*
+Copyright 2022 The Skaffold 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 cloudrun
+
+import (
+	"bufio"
+	"bytes"
+	"fmt"
+	"testing"
+
+	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/output"
+)
+
+func TestLogFormatter_Name(t *testing.T) {
+	serviceName := "test"
+	formatter := LogFormatter{prefix: serviceName, outputColor: output.Red}
+	if formatter.Name() != serviceName {
+		t.Fatalf("expected service name to be %s but got %s", serviceName, formatter.Name())
+	}
+}
+
+func TestLogFormatter_Printline(t *testing.T) {
+	testLog := "Testing log output"
+	serviceName := "test"
+	var b bytes.Buffer
+	writer := bufio.NewWriter(&b)
+	formatter := LogFormatter{prefix: serviceName, outputColor: output.Red}
+	formatter.PrintLine(writer, testLog)
+	writer.Flush()
+	result := b.Bytes()
+	expectedLogOutput := fmt.Sprintf("[%s] %s", serviceName, testLog)
+	if string(result) != expectedLogOutput {
+		t.Fatalf("expected log output to be %s but got %s", expectedLogOutput, result)
+	}
+}
diff --git a/pkg/skaffold/deploy/cloudrun/log_test.go b/pkg/skaffold/deploy/cloudrun/log_test.go
new file mode 100644
index 000000000..7afdebd9e
--- /dev/null
+++ b/pkg/skaffold/deploy/cloudrun/log_test.go
@@ -0,0 +1,249 @@
+/*
+Copyright 2022 The Skaffold 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 cloudrun
+
+import (
+	"bufio"
+	"bytes"
+	"context"
+	"testing"
+
+	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/config"
+	sErrors "github.com/GoogleContainerTools/skaffold/pkg/skaffold/errors"
+	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/output"
+	"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
+	"github.com/GoogleContainerTools/skaffold/proto/v1"
+)
+
+type testConfig struct {
+	tail bool
+}
+
+func (t *testConfig) Tail() bool {
+	return t.tail
+}
+
+func (t *testConfig) Mode() config.RunMode {
+	return config.RunModes.Run
+}
+
+func (t *testConfig) PortForwardOptions() config.PortForwardOptions {
+	return config.PortForwardOptions{}
+}
+
+func (t *testConfig) PortForwardResources() []*latest.PortForwardResource {
+	return nil
+}
+func newLogTestConfig(tail bool) *testConfig {
+	return &testConfig{tail: tail}
+}
+func TestNewLoggerAggregator(t *testing.T) {
+	tests := []struct {
+		name       string
+		tail       bool
+		numTailers int
+	}{
+		{
+			name:       "tailing is turned on",
+			tail:       true,
+			numTailers: 1,
+		},
+		{
+			name:       "tailing is turned off",
+			tail:       false,
+			numTailers: 0,
+		},
+	}
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			cfg := newLogTestConfig(test.tail)
+			logAggregator := NewLoggerAggregator(cfg, "test")
+			if len(logAggregator.logTailers) != test.numTailers {
+				t.Fatalf("expected %d forwarders, but got %v", test.numTailers, logAggregator.logTailers)
+			}
+		})
+	}
+}
+
+func TestResourcesAddedLogTailers(t *testing.T) {
+	tests := []struct {
+		name      string
+		resources []RunResourceName
+		outputs   []logTailerResource
+	}{
+		{
+			name: "one service with one color",
+			resources: []RunResourceName{
+				{
+					Project: "test-proj",
+					Region:  "test-region",
+					Service: "test-service",
+				},
+			},
+			outputs: []logTailerResource{
+				{
+					name: RunResourceName{
+						Project: "test-proj",
+						Region:  "test-region",
+						Service: "test-service",
+					},
+					formatter: LogFormatter{
+						prefix:      "test-service",
+						outputColor: output.DefaultColorCodes[0],
+					},
+					isTailing: false,
+				},
+			},
+		},
+		{
+			name: "two services with same name",
+			resources: []RunResourceName{
+				{
+					Project: "test-proj",
+					Region:  "test-region",
+					Service: "test-service",
+				},
+				{
+					Project: "test-proj",
+					Region:  "test-region",
+					Service: "test-service",
+				},
+			},
+			outputs: []logTailerResource{
+				{
+					name: RunResourceName{
+						Project: "test-proj",
+						Region:  "test-region",
+						Service: "test-service",
+					},
+					formatter: LogFormatter{
+						prefix:      "test-service",
+						outputColor: output.DefaultColorCodes[0],
+					},
+					isTailing: true,
+				},
+			},
+		},
+		{
+			name: "two services with different names",
+			resources: []RunResourceName{
+				{
+					Project: "test-proj",
+					Region:  "test-region",
+					Service: "test-service",
+				},
+				{
+					Project: "test-proj",
+					Region:  "test-region",
+					Service: "test-service2",
+				},
+			},
+			outputs: []logTailerResource{
+				{
+					name: RunResourceName{
+						Project: "test-proj",
+						Region:  "test-region",
+						Service: "test-service",
+					},
+					formatter: LogFormatter{
+						prefix:      "test-service",
+						outputColor: output.DefaultColorCodes[0],
+					},
+					isTailing: false,
+				},
+				{
+					name: RunResourceName{
+						Project: "test-proj",
+						Region:  "test-region",
+						Service: "test-service2",
+					},
+					formatter: LogFormatter{
+						prefix:      "test-service2",
+						outputColor: output.DefaultColorCodes[1],
+					},
+					isTailing: false,
+				},
+			},
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			cfg := newLogTestConfig(true)
+			logAggregator := NewLoggerAggregator(cfg, "")
+			for _, resource := range test.resources {
+				logAggregator.AddResource(resource)
+			}
+			if len(test.outputs) != len(logAggregator.resources.resources) {
+				t.Fatalf("Mismatch in expected outputs. Expected %v, got %v", test.outputs, logAggregator.resources.resources)
+			}
+			for _, result := range test.outputs {
+				got, found := logAggregator.resources.resources[result.name]
+				if !found {
+					t.Fatalf("expected to find log resource %v but got nothing", result.name)
+				}
+				if result.name != got.name || result.formatter != got.formatter {
+					t.Fatalf("did not get expected result. Expected %v, got %v", result, got)
+				}
+			}
+		})
+	}
+}
+
+func TestGcloudFoundLogTailing(t *testing.T) {
+	tests := []struct {
+		name         string
+		gcloudFound  bool
+		expectStatus proto.StatusCode
+	}{
+		{
+			name:        "gcloud found",
+			gcloudFound: true,
+		},
+		{
+			name:         "gcloud not found",
+			gcloudFound:  false,
+			expectStatus: proto.StatusCode_LOG_STREAMING_RUN_GCLOUD_NOT_FOUND,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			logTailers := runLogTailer{resources: &loggerTracker{}}
+			gcloudInstalled = func() bool { return test.gcloudFound }
+			ctx := context.Background()
+			var b bytes.Buffer
+			writer := bufio.NewWriter(&b)
+			err := logTailers.Start(ctx, writer)
+			writer.Flush()
+			result := b.Bytes()
+			if test.expectStatus == proto.StatusCode_OK {
+				if err != nil {
+					t.Fatalf("expected success, got error: %v with output %s", err, string(result))
+				}
+			} else {
+				if err == nil {
+					t.Fatalf("expected failure with code %v, got success with output: %s", test.expectStatus, string(result))
+				}
+				sErr := err.(*sErrors.ErrDef)
+				if sErr.StatusCode() != test.expectStatus {
+					t.Fatalf("expected failure with code %v, got code %v with output: %s", test.expectStatus, sErr.StatusCode(), string(result))
+				}
+			}
+		})
+	}
+}