Repository: GoogleContainerTools/skaffold
Pull request #8108 (2022-11-17 18:35:53)

fix: examples schema check failing
<!-- Thank you for your contribution! -->

<!-- Include if applicable: -->
Fixes: #8109 <!-- tracking issues that this PR will close -->


codecov[bot]: # [Codecov](https://codecov.io/gh/GoogleContainerTools/skaffold/pull/8108?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleContainerTools) Report
> Merging [#8108](https://codecov.io/gh/GoogleContainerTools/skaffold/pull/8108?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleContainerTools) (e9efd49) 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.07%`.
> The diff coverage is `53.26%`.

```diff
@@            Coverage Diff             @@
##             main    #8108      +/-   ##
==========================================
- Coverage   70.48%   66.40%   -4.08%     
==========================================
  Files         515      597      +82     
  Lines       23150    29177    +6027     
==========================================
+ Hits        16317    19376    +3059     
- Misses       5776     8350    +2574     
- Partials     1057     1451     +394     
```


| [Impacted Files](https://codecov.io/gh/GoogleContainerTools/skaffold/pull/8108?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/8108/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/8108/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/8108/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/8108/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/8108/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/8108/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/8108/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/8108/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/8108/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/8108/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/8108/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/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))
+				}
+			}
+		})
+	}
+}