github.com/GoogleContainerTools/skaffold/v2@v2.13.2/integration/render_test.go (about)

     1  /*
     2  Copyright 2019 The Skaffold Authors
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package integration
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"fmt"
    23  	"os"
    24  	"path"
    25  	"path/filepath"
    26  	"regexp"
    27  	"testing"
    28  
    29  	"gopkg.in/yaml.v2"
    30  
    31  	"github.com/GoogleContainerTools/skaffold/v2/integration/skaffold"
    32  	"github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/graph"
    33  	"github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/render"
    34  	"github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/render/renderer/kubectl"
    35  	"github.com/GoogleContainerTools/skaffold/v2/pkg/skaffold/schema/latest"
    36  	"github.com/GoogleContainerTools/skaffold/v2/testutil"
    37  )
    38  
    39  func TestKubectlRenderOutput(t *testing.T) {
    40  	ns, _ := SetupNamespace(t)
    41  	test := struct {
    42  		description string
    43  		builds      []graph.Artifact
    44  		input       string
    45  		expectedOut string
    46  	}{
    47  		description: "write rendered manifest to provided filepath",
    48  		builds: []graph.Artifact{
    49  			{
    50  				ImageName: "us-central1-docker.pkg.dev/k8s-skaffold/testing/skaffold",
    51  				Tag:       "us-central1-docker.pkg.dev/k8s-skaffold/testing/skaffold:test",
    52  			},
    53  		},
    54  		input: `apiVersion: v1
    55  kind: Pod
    56  spec:
    57    containers:
    58    - image: us-central1-docker.pkg.dev/k8s-skaffold/testing/skaffold
    59      name: skaffold
    60  `,
    61  		expectedOut: fmt.Sprintf(`apiVersion: v1
    62  kind: Pod
    63  metadata:
    64    namespace: %s
    65  spec:
    66    containers:
    67    - image: us-central1-docker.pkg.dev/k8s-skaffold/testing/skaffold:test
    68      name: skaffold`, ns.Name)}
    69  
    70  	testutil.Run(t, test.description, func(t *testutil.T) {
    71  		MarkIntegrationTest(t.T, CanRunWithoutGcp)
    72  		tmpDir := t.NewTempDir()
    73  		tmpDir.Write("deployment.yaml", test.input).Chdir()
    74  
    75  		rc := latest.RenderConfig{
    76  			Generate: latest.Generate{
    77  				RawK8s: []string{"deployment.yaml"}},
    78  		}
    79  		mockCfg := render.MockConfig{WorkingDir: tmpDir.Root()}
    80  		r, err := kubectl.New(mockCfg, rc, map[string]string{}, "default", ns.Name, nil, true)
    81  		t.RequireNoError(err)
    82  		var b bytes.Buffer
    83  		l, err := r.Render(context.Background(), &b, test.builds, false)
    84  
    85  		t.CheckNoError(err)
    86  
    87  		t.CheckDeepEqual(test.expectedOut, l.String(), testutil.YamlObj(t.T))
    88  	})
    89  }
    90  
    91  func TestKubectlRender(t *testing.T) {
    92  	ns, _ := SetupNamespace(t)
    93  	tests := []struct {
    94  		description string
    95  		builds      []graph.Artifact
    96  		input       string
    97  		expectedOut string
    98  	}{
    99  		{
   100  			description: "normal render",
   101  			builds: []graph.Artifact{
   102  				{
   103  					ImageName: "us-central1-docker.pkg.dev/k8s-skaffold/testing/skaffold",
   104  					Tag:       "us-central1-docker.pkg.dev/k8s-skaffold/testing/skaffold:test",
   105  				},
   106  			},
   107  			input: `apiVersion: v1
   108  kind: Pod
   109  metadata:
   110    name: my-pod-123
   111  spec:
   112    containers:
   113    - image: us-central1-docker.pkg.dev/k8s-skaffold/testing/skaffold
   114      name: skaffold
   115  `,
   116  			expectedOut: fmt.Sprintf(`apiVersion: v1
   117  kind: Pod
   118  metadata:
   119    name: my-pod-123
   120    namespace: %s
   121  spec:
   122    containers:
   123    - image: us-central1-docker.pkg.dev/k8s-skaffold/testing/skaffold:test
   124      name: skaffold`, ns.Name),
   125  		},
   126  		{
   127  			description: "two artifacts",
   128  			builds: []graph.Artifact{
   129  				{
   130  					ImageName: "gcr.io/project/image1",
   131  					Tag:       "gcr.io/project/image1:tag1",
   132  				},
   133  				{
   134  					ImageName: "gcr.io/project/image2",
   135  					Tag:       "gcr.io/project/image2:tag2",
   136  				},
   137  			},
   138  			input: `apiVersion: v1
   139  kind: Pod
   140  metadata:
   141    name: my-pod-123
   142  spec:
   143    containers:
   144    - image: gcr.io/project/image1
   145      name: image1
   146    - image: gcr.io/project/image2
   147      name: image2
   148  `,
   149  			expectedOut: fmt.Sprintf(`apiVersion: v1
   150  kind: Pod
   151  metadata:
   152    name: my-pod-123
   153    namespace: %s
   154  spec:
   155    containers:
   156    - image: gcr.io/project/image1:tag1
   157      name: image1
   158    - image: gcr.io/project/image2:tag2
   159      name: image2`, ns.Name),
   160  		},
   161  		{
   162  			description: "two artifacts, combined manifests",
   163  			builds: []graph.Artifact{
   164  				{
   165  					ImageName: "gcr.io/project/image1",
   166  					Tag:       "gcr.io/project/image1:tag1",
   167  				},
   168  				{
   169  					ImageName: "gcr.io/project/image2",
   170  					Tag:       "gcr.io/project/image2:tag2",
   171  				},
   172  			},
   173  			input: `apiVersion: v1
   174  kind: Pod
   175  metadata:
   176    name: my-pod-123
   177  spec:
   178    containers:
   179    - image: gcr.io/project/image1
   180      name: image1
   181  ---
   182  apiVersion: v1
   183  kind: Pod
   184  metadata:
   185    name: my-pod-456
   186  spec:
   187    containers:
   188    - image: gcr.io/project/image2
   189      name: image2
   190  `,
   191  			expectedOut: fmt.Sprintf(`apiVersion: v1
   192  kind: Pod
   193  metadata:
   194    name: my-pod-123
   195    namespace: %s
   196  spec:
   197    containers:
   198    - image: gcr.io/project/image1:tag1
   199      name: image1
   200  ---
   201  apiVersion: v1
   202  kind: Pod
   203  metadata:
   204    name: my-pod-456
   205    namespace: %s
   206  spec:
   207    containers:
   208    - image: gcr.io/project/image2:tag2
   209      name: image2`, ns.Name, ns.Name),
   210  		},
   211  	}
   212  	for _, test := range tests {
   213  		testutil.Run(t, test.description, func(t *testutil.T) {
   214  			MarkIntegrationTest(t.T, CanRunWithoutGcp)
   215  			tmpDir := t.NewTempDir()
   216  			tmpDir.Write("deployment.yaml", test.input).
   217  				Chdir()
   218  			rc := latest.RenderConfig{
   219  				Generate: latest.Generate{
   220  					RawK8s: []string{"deployment.yaml"}},
   221  			}
   222  			mockCfg := render.MockConfig{WorkingDir: tmpDir.Root()}
   223  			r, err := kubectl.New(mockCfg, rc, map[string]string{}, "default", ns.Name, nil, true)
   224  			t.RequireNoError(err)
   225  			var b bytes.Buffer
   226  			l, err := r.Render(context.Background(), &b, test.builds, false)
   227  
   228  			t.CheckNoError(err)
   229  			t.CheckDeepEqual(test.expectedOut, l.String(), testutil.YamlObj(t.T))
   230  		})
   231  	}
   232  }
   233  
   234  func TestHelmRender(t *testing.T) {
   235  	tests := []struct {
   236  		description      string
   237  		dir              string
   238  		args             []string
   239  		builds           []graph.Artifact
   240  		helmReleases     []latest.HelmRelease
   241  		expectedOut      string
   242  		withoutBuildJSON bool
   243  	}{
   244  		{
   245  			description: "Bare bones render",
   246  			dir:         "testdata/gke_loadbalancer-render",
   247  			expectedOut: `apiVersion: v1
   248  kind: Service
   249  metadata:
   250    labels:
   251      app: gke-loadbalancer
   252      skaffold.dev/run-id: phony-run-id
   253    name: gke-loadbalancer
   254  spec:
   255    ports:
   256    - name: http
   257      port: 80
   258      protocol: TCP
   259      targetPort: 3000
   260    selector:
   261      app: gke-loadbalancer
   262    type: LoadBalancer
   263  ---
   264  apiVersion: apps/v1
   265  kind: Deployment
   266  metadata:
   267    labels:
   268      app: gke-loadbalancer
   269      skaffold.dev/run-id: phony-run-id
   270    name: gke-loadbalancer
   271  spec:
   272    replicas: 1
   273    selector:
   274      matchLabels:
   275        app: gke-loadbalancer
   276    template:
   277      metadata:
   278        labels:
   279          app: gke-loadbalancer
   280          skaffold.dev/run-id: phony-run-id
   281      spec:
   282        containers:
   283        - image: gke-loadbalancer:test
   284          name: gke-container
   285          ports:
   286          - containerPort: 3000
   287  `,
   288  		},
   289  		{
   290  			description: "A more complex template",
   291  			dir:         "testdata/helm-render",
   292  			args:        []string{"--profile=helm-render"},
   293  			expectedOut: `apiVersion: v1
   294  kind: Service
   295  metadata:
   296    labels:
   297      app: skaffold-helm
   298      chart: skaffold-helm-0.1.0
   299      heritage: Helm
   300      release: skaffold-helm
   301      skaffold.dev/run-id: phony-run-id
   302    name: skaffold-helm-skaffold-helm
   303  spec:
   304    ports:
   305    - name: nginx
   306      port: 80
   307      protocol: TCP
   308      targetPort: 80
   309    selector:
   310      app: skaffold-helm
   311      release: skaffold-helm
   312    type: ClusterIP
   313  ---
   314  apiVersion: apps/v1
   315  kind: Deployment
   316  metadata:
   317    labels:
   318      app: skaffold-helm
   319      chart: skaffold-helm-0.1.0
   320      heritage: Helm
   321      release: skaffold-helm
   322      skaffold.dev/run-id: phony-run-id
   323    name: skaffold-helm
   324  spec:
   325    replicas: 1
   326    selector:
   327      matchLabels:
   328        app: skaffold-helm
   329        release: skaffold-helm
   330    template:
   331      metadata:
   332        labels:
   333          app: skaffold-helm
   334          release: skaffold-helm
   335          skaffold.dev/run-id: phony-run-id
   336      spec:
   337        containers:
   338        - image: us-central1-docker.pkg.dev/k8s-skaffold/testing/skaffold-helm:sha256-nonsenselettersandnumbers
   339          imagePullPolicy: always
   340          name: skaffold-helm
   341          ports:
   342          - containerPort: 80
   343          resources: {}
   344  ---
   345  apiVersion: networking.k8s.io/v1
   346  kind: Ingress
   347  metadata:
   348    annotations: null
   349    labels:
   350      app: skaffold-helm
   351      chart: skaffold-helm-0.1.0
   352      heritage: Helm
   353      release: skaffold-helm
   354    name: skaffold-helm-skaffold-helm
   355  spec:
   356    rules:
   357    - http:
   358        paths:
   359        - backend:
   360            service:
   361              name: skaffold-helm-skaffold-helm
   362              port:
   363                number: 80
   364          path: /
   365          pathType: ImplementationSpecific
   366  `,
   367  		}, {
   368  			description:      "Template with Release.namespace set from skaffold.yaml file deploy.helm.releases.namespace",
   369  			dir:              "testdata/helm-deploy-namespace",
   370  			withoutBuildJSON: true,
   371  			expectedOut: `apiVersion: apps/v1
   372  kind: Deployment
   373  metadata:
   374    labels:
   375      app: skaffold-helm
   376      skaffold.dev/run-id: phony-run-id
   377    name: skaffold-helm
   378    namespace: helm-namespace
   379  spec:
   380    replicas: 2
   381    selector:
   382      matchLabels:
   383        app: skaffold-helm
   384    template:
   385      metadata:
   386        labels:
   387          app: skaffold-helm
   388          skaffold.dev/run-id: phony-run-id
   389      spec:
   390        containers:
   391        - image: skaffold-helm:latest
   392          name: skaffold-helm
   393  `,
   394  		}, {
   395  			description:      "Template with Release.namespace set from skaffold.yaml file manifests.helm.releases.namespace",
   396  			dir:              "testdata/helm-manifests-namespace",
   397  			withoutBuildJSON: true,
   398  			expectedOut: `apiVersion: apps/v1
   399  kind: Deployment
   400  metadata:
   401    labels:
   402      app: skaffold-helm
   403      skaffold.dev/run-id: phony-run-id
   404    name: skaffold-helm
   405    namespace: helm-namespace
   406  spec:
   407    replicas: 2
   408    selector:
   409      matchLabels:
   410        app: skaffold-helm
   411    template:
   412      metadata:
   413        labels:
   414          app: skaffold-helm
   415          skaffold.dev/run-id: phony-run-id
   416      spec:
   417        containers:
   418        - image: skaffold-helm:latest
   419          name: skaffold-helm
   420  `,
   421  		}, {
   422  			description:      "Template with Release.namespace set from skaffold.yaml file manifests.helm.releases.namespace and deploy.helm.releases.namespace",
   423  			dir:              "testdata/helm-manifests-and-deploy-namespace",
   424  			withoutBuildJSON: true,
   425  			expectedOut: `apiVersion: apps/v1
   426  kind: Deployment
   427  metadata:
   428    labels:
   429      app: skaffold-helm
   430      skaffold.dev/run-id: phony-run-id
   431    name: skaffold-helm
   432    namespace: helm-namespace-1
   433  spec:
   434    replicas: 2
   435    selector:
   436      matchLabels:
   437        app: skaffold-helm
   438    template:
   439      metadata:
   440        labels:
   441          app: skaffold-helm
   442          skaffold.dev/run-id: phony-run-id
   443      spec:
   444        containers:
   445        - image: skaffold-helm:latest
   446          name: skaffold-helm
   447  `,
   448  		}, {
   449  			description:      "Template with Release.namespace set from skaffold.yaml file deploy.helm.releases.namespace - v1 skaffold schema",
   450  			dir:              "testdata/helm-deploy-namespace-v1-schema",
   451  			withoutBuildJSON: true,
   452  			expectedOut: `apiVersion: apps/v1
   453  kind: Deployment
   454  metadata:
   455    labels:
   456      app: skaffold-helm
   457      skaffold.dev/run-id: phony-run-id
   458    name: skaffold-helm
   459    namespace: helm-namespace
   460  spec:
   461    replicas: 2
   462    selector:
   463      matchLabels:
   464        app: skaffold-helm
   465    template:
   466      metadata:
   467        labels:
   468          app: skaffold-helm
   469          skaffold.dev/run-id: phony-run-id
   470      spec:
   471        containers:
   472        - image: skaffold-helm:latest
   473          name: skaffold-helm
   474  `,
   475  		},
   476  		{
   477  			description:      "Template replicaCount with --set flag",
   478  			dir:              "testdata/helm-render-simple",
   479  			args:             []string{"--set", "replicaCount=3"},
   480  			withoutBuildJSON: true,
   481  			expectedOut: `apiVersion: apps/v1
   482  kind: Deployment
   483  metadata:
   484    labels:
   485      app: skaffold-helm
   486      skaffold.dev/run-id: phony-run-id
   487    name: skaffold-helm
   488    namespace: helm-namespace
   489  spec:
   490    replicas: 3
   491    selector:
   492      matchLabels:
   493        app: skaffold-helm
   494    template:
   495      metadata:
   496        labels:
   497          app: skaffold-helm
   498          skaffold.dev/run-id: phony-run-id
   499      spec:
   500        containers:
   501        - image: skaffold-helm:latest
   502          name: skaffold-helm
   503  `,
   504  		},
   505  		{
   506  			description:      "With Helm global flags",
   507  			dir:              "testdata/helm-render",
   508  			args:             []string{"-p", "helm-render-with-global-flags"},
   509  			withoutBuildJSON: true,
   510  			expectedOut: `apiVersion: v1
   511  kind: Service
   512  metadata:
   513    labels:
   514      app: skaffold-helm
   515      chart: skaffold-helm-0.1.0
   516      heritage: Helm
   517      release: skaffold-helm
   518      skaffold.dev/run-id: phony-run-id
   519    name: skaffold-helm-skaffold-helm
   520  spec:
   521    ports:
   522    - name: nginx
   523      port: 80
   524      protocol: TCP
   525      targetPort: 80
   526    selector:
   527      app: skaffold-helm
   528      release: skaffold-helm
   529    type: ClusterIP
   530  ---
   531  apiVersion: apps/v1
   532  kind: Deployment
   533  metadata:
   534    labels:
   535      app: skaffold-helm
   536      chart: skaffold-helm-0.1.0
   537      heritage: Helm
   538      release: skaffold-helm
   539      skaffold.dev/run-id: phony-run-id
   540    name: skaffold-helm
   541  spec:
   542    replicas: 1
   543    selector:
   544      matchLabels:
   545        app: skaffold-helm
   546        release: skaffold-helm
   547    template:
   548      metadata:
   549        labels:
   550          app: skaffold-helm
   551          release: skaffold-helm
   552          skaffold.dev/run-id: phony-run-id
   553      spec:
   554        containers:
   555        - image: us-central1-docker.pkg.dev/k8s-skaffold/testing/skaffold-helm:latest
   556          imagePullPolicy: always
   557          name: skaffold-helm
   558          ports:
   559          - containerPort: 80
   560          resources: {}
   561  ---
   562  apiVersion: networking.k8s.io/v1
   563  kind: Ingress
   564  metadata:
   565    annotations: null
   566    labels:
   567      app: skaffold-helm
   568      chart: skaffold-helm-0.1.0
   569      heritage: Helm
   570      release: skaffold-helm
   571    name: skaffold-helm-skaffold-helm
   572  spec:
   573    rules:
   574    - http:
   575        paths:
   576        - backend:
   577            service:
   578              name: skaffold-helm-skaffold-helm
   579              port:
   580                number: 80
   581          path: /
   582          pathType: ImplementationSpecific
   583  `,
   584  		},
   585  	}
   586  	for _, test := range tests {
   587  		t.Run(test.description, func(t *testing.T) {
   588  			MarkIntegrationTest(t, CanRunWithoutGcp)
   589  
   590  			args := []string{"--default-repo=", "--label=skaffold.dev/run-id=phony-run-id"}
   591  			if !test.withoutBuildJSON {
   592  				args = append(args, "--build-artifacts=builds.out.json")
   593  			}
   594  			args = append(args, test.args...)
   595  
   596  			out := skaffold.Render(args...).InDir(test.dir).RunOrFailOutput(t)
   597  
   598  			testutil.CheckDeepEqual(t, test.expectedOut, string(out), testutil.YamlObj(t))
   599  		})
   600  	}
   601  }
   602  
   603  func TestRenderWithBuilds(t *testing.T) {
   604  	tests := []struct {
   605  		description         string
   606  		config              string
   607  		buildOutputFilePath string
   608  		images              string
   609  		offline             bool
   610  		input               map[string]string // file path => content
   611  		expectedOut         string
   612  		namespaceFlag       string
   613  	}{
   614  		{
   615  			description: "kubectl render from build output, online, no labels",
   616  			config: `
   617  apiVersion: skaffold/v2alpha1
   618  kind: Config
   619  
   620  # Irrelevant for rendering from previous build output
   621  build:
   622    artifacts: []
   623  
   624  deploy:
   625    kubectl:
   626      manifests:
   627        - deployment.yaml
   628  `,
   629  			buildOutputFilePath: "testdata/render/build-output.json",
   630  			offline:             false,
   631  			input: map[string]string{"deployment.yaml": `
   632  apiVersion: v1
   633  kind: Pod
   634  metadata:
   635    name: my-pod-123
   636  spec:
   637    containers:
   638    - image: 12345.dkr.ecr.eu-central-1.amazonaws.com/my/project-a
   639      name: a
   640    - image: gcr.io/my/project-b
   641      name: b
   642  `},
   643  			expectedOut: `apiVersion: v1
   644  kind: Pod
   645  metadata:
   646    name: my-pod-123
   647  spec:
   648    containers:
   649    - image: 12345.dkr.ecr.eu-central-1.amazonaws.com/my/project-a:4da6a56988057d23f68a4e988f4905dd930ea438-dirty@sha256:d8a33c260c50385ea54077bc7032dba0a860dc8870464f6795fd0aa548d117bf
   650      name: a
   651    - image: gcr.io/my/project-b:764841f8bac17e625724adcbf0d28013f22d058f-dirty@sha256:79e160161fd8190acae2d04d8f296a27a562c8a59732c64ac71c99009a6e89bc
   652      name: b
   653  `,
   654  		},
   655  		{
   656  			description: "kubectl render from build output, offline, no labels",
   657  			config: `
   658  apiVersion: skaffold/v2alpha1
   659  kind: Config
   660  
   661  # Irrelevant for rendering from previous build output
   662  build:
   663    artifacts: []
   664  
   665  deploy:
   666    kubectl:
   667      manifests:
   668        - deployment.yaml
   669  `,
   670  			buildOutputFilePath: "testdata/render/build-output.json",
   671  			offline:             true,
   672  			input: map[string]string{"deployment.yaml": `
   673  apiVersion: v1
   674  kind: Pod
   675  metadata:
   676    name: my-pod-123
   677  spec:
   678    containers:
   679    - image: 12345.dkr.ecr.eu-central-1.amazonaws.com/my/project-a
   680      name: a
   681    - image: gcr.io/my/project-b
   682      name: b
   683  `},
   684  			// No `metadata.namespace` in offline mode
   685  			expectedOut: `apiVersion: v1
   686  kind: Pod
   687  metadata:
   688    name: my-pod-123
   689  spec:
   690    containers:
   691    - image: 12345.dkr.ecr.eu-central-1.amazonaws.com/my/project-a:4da6a56988057d23f68a4e988f4905dd930ea438-dirty@sha256:d8a33c260c50385ea54077bc7032dba0a860dc8870464f6795fd0aa548d117bf
   692      name: a
   693    - image: gcr.io/my/project-b:764841f8bac17e625724adcbf0d28013f22d058f-dirty@sha256:79e160161fd8190acae2d04d8f296a27a562c8a59732c64ac71c99009a6e89bc
   694      name: b
   695  `,
   696  		},
   697  
   698  		{
   699  			description: "kubectl render from build output, offline, with labels",
   700  			config: `
   701  apiVersion: skaffold/v2alpha1
   702  kind: Config
   703  
   704  # Irrelevant for rendering from previous build output
   705  build:
   706    artifacts: []
   707  
   708  deploy:
   709    kubectl:
   710      manifests:
   711        - deployment.yaml
   712  `,
   713  			buildOutputFilePath: "testdata/render/build-output.json",
   714  			offline:             true,
   715  			input: map[string]string{"deployment.yaml": `
   716  apiVersion: v1
   717  kind: Pod
   718  metadata:
   719    name: my-pod-123
   720  spec:
   721    containers:
   722    - image: 12345.dkr.ecr.eu-central-1.amazonaws.com/my/project-a
   723      name: a
   724    - image: gcr.io/my/project-b
   725      name: b
   726  `},
   727  			// No `metadata.namespace` in offline mode
   728  			expectedOut: `apiVersion: v1
   729  kind: Pod
   730  metadata:
   731    name: my-pod-123
   732  spec:
   733    containers:
   734    - image: 12345.dkr.ecr.eu-central-1.amazonaws.com/my/project-a:4da6a56988057d23f68a4e988f4905dd930ea438-dirty@sha256:d8a33c260c50385ea54077bc7032dba0a860dc8870464f6795fd0aa548d117bf
   735      name: a
   736    - image: gcr.io/my/project-b:764841f8bac17e625724adcbf0d28013f22d058f-dirty@sha256:79e160161fd8190acae2d04d8f296a27a562c8a59732c64ac71c99009a6e89bc
   737      name: b
   738  `,
   739  		},
   740  
   741  		{
   742  			description: "kustomize render from build output, offline, no labels",
   743  			config: `
   744  apiVersion: skaffold/v2alpha1
   745  kind: Config
   746  
   747  # Irrelevant for rendering from previous build output
   748  build:
   749    artifacts: []
   750  
   751  deploy:
   752    kustomize: {} # defaults to current working directory
   753  `,
   754  			buildOutputFilePath: "testdata/render/build-output.json",
   755  			offline:             true,
   756  			input: map[string]string{"deployment.yaml": `
   757  apiVersion: v1
   758  kind: Pod
   759  metadata:
   760    name: my-pod-123
   761  spec:
   762    containers:
   763    - image: 12345.dkr.ecr.eu-central-1.amazonaws.com/my/project-a
   764      name: a
   765    - image: gcr.io/my/project-b
   766      name: b
   767  `,
   768  				"kustomization.yaml": `
   769  commonLabels:
   770    this-is-from: kustomization.yaml
   771  
   772  resources:
   773    - deployment.yaml
   774  `},
   775  			// No `metadata.namespace` in offline mode
   776  			expectedOut: `apiVersion: v1
   777  kind: Pod
   778  metadata:
   779    labels:
   780      this-is-from: kustomization.yaml
   781    name: my-pod-123
   782  spec:
   783    containers:
   784    - image: 12345.dkr.ecr.eu-central-1.amazonaws.com/my/project-a:4da6a56988057d23f68a4e988f4905dd930ea438-dirty@sha256:d8a33c260c50385ea54077bc7032dba0a860dc8870464f6795fd0aa548d117bf
   785      name: a
   786    - image: gcr.io/my/project-b:764841f8bac17e625724adcbf0d28013f22d058f-dirty@sha256:79e160161fd8190acae2d04d8f296a27a562c8a59732c64ac71c99009a6e89bc
   787      name: b
   788  `,
   789  		},
   790  
   791  		{
   792  			description: "kustomize render from build output, offline, with labels",
   793  			config: `
   794  apiVersion: skaffold/v2alpha1
   795  kind: Config
   796  
   797  # Irrelevant for rendering from previous build output
   798  build:
   799    artifacts: []
   800  
   801  deploy:
   802    kustomize: {} # defaults to current working directory
   803  `,
   804  			buildOutputFilePath: "testdata/render/build-output.json",
   805  			offline:             true,
   806  			input: map[string]string{"deployment.yaml": `
   807  apiVersion: v1
   808  kind: Pod
   809  metadata:
   810    name: my-pod-123
   811  spec:
   812    containers:
   813    - image: 12345.dkr.ecr.eu-central-1.amazonaws.com/my/project-a
   814      name: a
   815    - image: gcr.io/my/project-b
   816      name: b
   817  `,
   818  				"kustomization.yaml": `
   819  commonLabels:
   820    this-is-from: kustomization.yaml
   821  
   822  resources:
   823    - deployment.yaml
   824  `},
   825  			// No `metadata.namespace` in offline mode
   826  			expectedOut: `apiVersion: v1
   827  kind: Pod
   828  metadata:
   829    labels:
   830      this-is-from: kustomization.yaml
   831    name: my-pod-123
   832  spec:
   833    containers:
   834    - image: 12345.dkr.ecr.eu-central-1.amazonaws.com/my/project-a:4da6a56988057d23f68a4e988f4905dd930ea438-dirty@sha256:d8a33c260c50385ea54077bc7032dba0a860dc8870464f6795fd0aa548d117bf
   835      name: a
   836    - image: gcr.io/my/project-b:764841f8bac17e625724adcbf0d28013f22d058f-dirty@sha256:79e160161fd8190acae2d04d8f296a27a562c8a59732c64ac71c99009a6e89bc
   837      name: b
   838  `,
   839  		},
   840  		{
   841  			description: "kustomize render from build output, offline=false",
   842  			config: `
   843  apiVersion: skaffold/v4beta2
   844  kind: Config
   845  
   846  # Irrelevant for rendering from previous build output
   847  build:
   848    artifacts: []
   849  
   850  manifests:
   851    kustomize:
   852      paths:
   853      - .
   854  `,
   855  			buildOutputFilePath: "testdata/render/build-output.json",
   856  			offline:             false,
   857  			input: map[string]string{"pod.yaml": `
   858  apiVersion: v1
   859  kind: Pod
   860  metadata:
   861    name: my-pod-123
   862  spec:
   863    containers:
   864    - image: 12345.dkr.ecr.eu-central-1.amazonaws.com/my/project-a
   865      name: a
   866    - image: gcr.io/my/project-b
   867      name: b
   868  `,
   869  				"kustomization.yaml": `
   870  commonLabels:
   871    this-is-from: kustomization.yaml
   872  
   873  resources:
   874    - pod.yaml
   875  `},
   876  			// No `metadata.namespace` should be injected
   877  			expectedOut: `apiVersion: v1
   878  kind: Pod
   879  metadata:
   880    labels:
   881      this-is-from: kustomization.yaml
   882    name: my-pod-123
   883  spec:
   884    containers:
   885    - image: 12345.dkr.ecr.eu-central-1.amazonaws.com/my/project-a:4da6a56988057d23f68a4e988f4905dd930ea438-dirty@sha256:d8a33c260c50385ea54077bc7032dba0a860dc8870464f6795fd0aa548d117bf
   886      name: a
   887    - image: gcr.io/my/project-b:764841f8bac17e625724adcbf0d28013f22d058f-dirty@sha256:79e160161fd8190acae2d04d8f296a27a562c8a59732c64ac71c99009a6e89bc
   888      name: b
   889  `,
   890  		},
   891  		{
   892  			description: "kustomize + rawYaml render from build output, offline=false",
   893  			config: `
   894  apiVersion: skaffold/v4beta2
   895  kind: Config
   896  
   897  # Irrelevant for rendering from previous build output
   898  build:
   899    artifacts: []
   900  
   901  manifests:
   902    rawYaml:
   903      - pod2.yaml
   904    kustomize:
   905      paths:
   906      - .
   907  `,
   908  			buildOutputFilePath: "testdata/render/build-output.json",
   909  			offline:             false,
   910  			input: map[string]string{"pod1.yaml": `
   911  apiVersion: v1
   912  kind: Pod
   913  metadata:
   914    name: my-pod-1
   915  spec:
   916    containers:
   917    - image: 12345.dkr.ecr.eu-central-1.amazonaws.com/my/project-a
   918      name: a
   919    - image: gcr.io/my/project-b
   920      name: b
   921  `,
   922  				"pod2.yaml": `
   923  apiVersion: v1
   924  kind: Pod
   925  metadata:
   926    name: my-pod-2
   927  spec:
   928    containers:
   929    - image: 12345.dkr.ecr.eu-central-1.amazonaws.com/my/project-a
   930      name: a
   931    - image: gcr.io/my/project-b
   932      name: b
   933  `,
   934  				"kustomization.yaml": `
   935  commonLabels:
   936    this-is-from: kustomization.yaml
   937  
   938  resources:
   939    - pod1.yaml
   940  `},
   941  			// No `metadata.namespace` should be injected in the manifest rendererd by kustomize
   942  			expectedOut: `apiVersion: v1
   943  kind: Pod
   944  metadata:
   945    name: my-pod-2
   946  spec:
   947    containers:
   948    - image: 12345.dkr.ecr.eu-central-1.amazonaws.com/my/project-a:4da6a56988057d23f68a4e988f4905dd930ea438-dirty@sha256:d8a33c260c50385ea54077bc7032dba0a860dc8870464f6795fd0aa548d117bf
   949      name: a
   950    - image: gcr.io/my/project-b:764841f8bac17e625724adcbf0d28013f22d058f-dirty@sha256:79e160161fd8190acae2d04d8f296a27a562c8a59732c64ac71c99009a6e89bc
   951      name: b
   952  ---
   953  apiVersion: v1
   954  kind: Pod
   955  metadata:
   956    labels:
   957      this-is-from: kustomization.yaml
   958    name: my-pod-1
   959  spec:
   960    containers:
   961    - image: 12345.dkr.ecr.eu-central-1.amazonaws.com/my/project-a:4da6a56988057d23f68a4e988f4905dd930ea438-dirty@sha256:d8a33c260c50385ea54077bc7032dba0a860dc8870464f6795fd0aa548d117bf
   962      name: a
   963    - image: gcr.io/my/project-b:764841f8bac17e625724adcbf0d28013f22d058f-dirty@sha256:79e160161fd8190acae2d04d8f296a27a562c8a59732c64ac71c99009a6e89bc
   964      name: b
   965  `,
   966  		},
   967  		{
   968  			description:   "kustomize + rawYaml render from build output, offline=false, with namespace flag",
   969  			namespaceFlag: "mynamespace",
   970  			config: `
   971  apiVersion: skaffold/v4beta2
   972  kind: Config
   973  
   974  # Irrelevant for rendering from previous build output
   975  build:
   976    artifacts: []
   977  
   978  manifests:
   979    rawYaml:
   980      - pod2.yaml
   981    kustomize:
   982      paths:
   983      - .
   984  `,
   985  			buildOutputFilePath: "testdata/render/build-output.json",
   986  			offline:             false,
   987  			input: map[string]string{"pod1.yaml": `
   988  apiVersion: v1
   989  kind: Pod
   990  metadata:
   991    name: my-pod-1
   992  spec:
   993    containers:
   994    - image: 12345.dkr.ecr.eu-central-1.amazonaws.com/my/project-a
   995      name: a
   996    - image: gcr.io/my/project-b
   997      name: b
   998  `,
   999  				"pod2.yaml": `
  1000  apiVersion: v1
  1001  kind: Pod
  1002  metadata:
  1003    name: my-pod-2
  1004  spec:
  1005    containers:
  1006    - image: 12345.dkr.ecr.eu-central-1.amazonaws.com/my/project-a
  1007      name: a
  1008    - image: gcr.io/my/project-b
  1009      name: b
  1010  `,
  1011  				"kustomization.yaml": `
  1012  commonLabels:
  1013    this-is-from: kustomization.yaml
  1014  
  1015  resources:
  1016    - pod1.yaml
  1017  `},
  1018  			// No `metadata.namespace` should be injected in the manifest rendererd by kustomize
  1019  			expectedOut: `apiVersion: v1
  1020  kind: Pod
  1021  metadata:
  1022    name: my-pod-2
  1023    namespace: mynamespace
  1024  spec:
  1025    containers:
  1026    - image: 12345.dkr.ecr.eu-central-1.amazonaws.com/my/project-a:4da6a56988057d23f68a4e988f4905dd930ea438-dirty@sha256:d8a33c260c50385ea54077bc7032dba0a860dc8870464f6795fd0aa548d117bf
  1027      name: a
  1028    - image: gcr.io/my/project-b:764841f8bac17e625724adcbf0d28013f22d058f-dirty@sha256:79e160161fd8190acae2d04d8f296a27a562c8a59732c64ac71c99009a6e89bc
  1029      name: b
  1030  ---
  1031  apiVersion: v1
  1032  kind: Pod
  1033  metadata:
  1034    namespace: mynamespace
  1035    labels:
  1036      this-is-from: kustomization.yaml
  1037    name: my-pod-1
  1038  spec:
  1039    containers:
  1040    - image: 12345.dkr.ecr.eu-central-1.amazonaws.com/my/project-a:4da6a56988057d23f68a4e988f4905dd930ea438-dirty@sha256:d8a33c260c50385ea54077bc7032dba0a860dc8870464f6795fd0aa548d117bf
  1041      name: a
  1042    - image: gcr.io/my/project-b:764841f8bac17e625724adcbf0d28013f22d058f-dirty@sha256:79e160161fd8190acae2d04d8f296a27a562c8a59732c64ac71c99009a6e89bc
  1043      name: b
  1044  `,
  1045  		},
  1046  		{
  1047  			description: "kubectl render with images",
  1048  			config: `
  1049  apiVersion: skaffold/v2alpha1
  1050  kind: Config
  1051  
  1052  # Irrelevant for rendering from previous build output
  1053  build:
  1054    artifacts: []
  1055  
  1056  deploy:
  1057    kubectl:
  1058      manifests:
  1059        - deployment.yaml
  1060  `,
  1061  			images:  "12345.dkr.ecr.eu-central-1.amazonaws.com/my/project-a:4da6a56988057d23f68a4e988f4905dd930ea438-dirty@sha256:d8a33c260c50385ea54077bc7032dba0a860dc8870464f6795fd0aa548d117bf,gcr.io/my/project-b:764841f8bac17e625724adcbf0d28013f22d058f-dirty@sha256:79e160161fd8190acae2d04d8f296a27a562c8a59732c64ac71c99009a6e89bc",
  1062  			offline: false,
  1063  			input: map[string]string{"deployment.yaml": `
  1064  apiVersion: v1
  1065  kind: Pod
  1066  metadata:
  1067    name: my-pod-123
  1068  spec:
  1069    containers:
  1070    - image: 12345.dkr.ecr.eu-central-1.amazonaws.com/my/project-a
  1071      name: a
  1072    - image: gcr.io/my/project-b
  1073      name: b
  1074  `},
  1075  			expectedOut: `apiVersion: v1
  1076  kind: Pod
  1077  metadata:
  1078    name: my-pod-123
  1079  spec:
  1080    containers:
  1081    - image: 12345.dkr.ecr.eu-central-1.amazonaws.com/my/project-a:4da6a56988057d23f68a4e988f4905dd930ea438-dirty@sha256:d8a33c260c50385ea54077bc7032dba0a860dc8870464f6795fd0aa548d117bf
  1082      name: a
  1083    - image: gcr.io/my/project-b:764841f8bac17e625724adcbf0d28013f22d058f-dirty@sha256:79e160161fd8190acae2d04d8f296a27a562c8a59732c64ac71c99009a6e89bc
  1084      name: b
  1085  `,
  1086  		},
  1087  	}
  1088  
  1089  	testDir, err := os.Getwd()
  1090  	if err != nil {
  1091  		t.Fatal(err)
  1092  	}
  1093  
  1094  	for _, test := range tests {
  1095  		testutil.Run(t, test.description, func(t *testutil.T) {
  1096  			MarkIntegrationTest(t.T, CanRunWithoutGcp)
  1097  			tmpDir := t.NewTempDir()
  1098  			tmpDir.Write("skaffold.yaml", test.config)
  1099  
  1100  			for filePath, content := range test.input {
  1101  				tmpDir.Write(filePath, content)
  1102  			}
  1103  
  1104  			tmpDir.Chdir()
  1105  
  1106  			// `--default-repo=` is used to cancel the default repo that is set by default.
  1107  			args := []string{"--default-repo=", "--digest-source=local", "--output", "rendered.yaml"}
  1108  			if test.buildOutputFilePath != "" {
  1109  				args = append(args, "--build-artifacts="+path.Join(testDir, test.buildOutputFilePath))
  1110  			} else {
  1111  				args = append(args, "--images="+test.images)
  1112  			}
  1113  
  1114  			if test.namespaceFlag != "" {
  1115  				args = append(args, "--namespace", test.namespaceFlag)
  1116  			}
  1117  
  1118  			if test.offline {
  1119  				env := []string{"KUBECONFIG=not-supposed-to-be-used-in-offline-mode"}
  1120  				args = append(args, "--offline=true")
  1121  				skaffold.Render(args...).WithEnv(env).RunOrFail(t.T)
  1122  			} else {
  1123  				skaffold.Render(args...).RunOrFail(t.T)
  1124  			}
  1125  
  1126  			fileContent, err := os.ReadFile("rendered.yaml")
  1127  			t.RequireNoError(err)
  1128  
  1129  			// Tests are written in a way that actual output is valid YAML
  1130  			parsed := make(map[string]interface{})
  1131  			err = yaml.UnmarshalStrict(fileContent, parsed)
  1132  			t.CheckNoError(err)
  1133  
  1134  			fileContentReplaced := regexp.MustCompile("(?m)(skaffold.dev/run-id|skaffold.dev/docker-api-version): .+$").ReplaceAll(fileContent, []byte("$1: SOMEDYNAMICVALUE"))
  1135  
  1136  			t.RequireNoError(err)
  1137  			t.CheckDeepEqual(test.expectedOut, string(fileContentReplaced), testutil.YamlObj(t.T))
  1138  		})
  1139  	}
  1140  }
  1141  
  1142  func TestRenderHydrationDirCreation(t *testing.T) {
  1143  	MarkIntegrationTest(t, CanRunWithoutGcp)
  1144  	const hydrationDir = "hydration-dir"
  1145  
  1146  	tests := []struct {
  1147  		description              string
  1148  		shouldCreateHydrationDir bool
  1149  		config                   string
  1150  		manifest                 string
  1151  	}{
  1152  		{
  1153  			description:              "project with kpt renderer should create hydration dir",
  1154  			shouldCreateHydrationDir: true,
  1155  			config: `
  1156  apiVersion: skaffold/v4beta1
  1157  kind: Config
  1158  
  1159  build:
  1160    artifacts: []
  1161  manifests:
  1162    kpt: []
  1163  `,
  1164  			manifest: `
  1165  apiVersion: v1
  1166  kind: Pod
  1167  metadata:
  1168    name: getting-started
  1169  spec:
  1170    containers:
  1171      - name: getting-started
  1172        image: skaffold-example`,
  1173  		},
  1174  		{
  1175  			description:              "project with kpt deployer should create hydration dir",
  1176  			shouldCreateHydrationDir: true,
  1177  			config: `
  1178  apiVersion: skaffold/v4beta1
  1179  kind: Config
  1180  
  1181  build:
  1182    artifacts: []
  1183  manifests:
  1184    kpt: []
  1185  deploy:
  1186    kpt: {}
  1187  `,
  1188  			manifest: `
  1189  apiVersion: v1
  1190  kind: Pod
  1191  metadata:
  1192    name: getting-started
  1193  spec:
  1194    containers:
  1195      - name: getting-started
  1196        image: skaffold-example`,
  1197  		},
  1198  		{
  1199  			description:              "project with rawYaml and transform should not create hydration dir (uses kpt renderer)",
  1200  			shouldCreateHydrationDir: false,
  1201  			config: `
  1202  apiVersion: skaffold/v4beta1
  1203  kind: Config
  1204  
  1205  build:
  1206    artifacts: []
  1207  manifests:
  1208    rawYaml:
  1209      - k8s/k8s-pod.yaml
  1210    transform:
  1211      - name: set-annotations
  1212        configMap:
  1213          - "author:fake-author"
  1214  `,
  1215  			manifest: `
  1216  apiVersion: v1
  1217  kind: Pod
  1218  metadata:
  1219    name: getting-started
  1220  spec:
  1221    containers:
  1222      - name: getting-started
  1223        image: skaffold-example`,
  1224  		},
  1225  		{
  1226  			description:              "project without kpt should not create hydration dir",
  1227  			shouldCreateHydrationDir: false,
  1228  			config: `
  1229  apiVersion: skaffold/v4beta1
  1230  kind: Config
  1231  
  1232  build:
  1233    artifacts: []
  1234  manifests:
  1235    rawYaml:
  1236      - k8s/k8s-pod.yaml
  1237  `,
  1238  			manifest: `
  1239  apiVersion: v1
  1240  kind: Pod
  1241  metadata:
  1242    name: getting-started
  1243  spec:
  1244    containers:
  1245    - name: getting-started
  1246      image: skaffold-example`,
  1247  		},
  1248  	}
  1249  
  1250  	for _, test := range tests {
  1251  		testutil.Run(t, test.description, func(t *testutil.T) {
  1252  			tmpDir := t.NewTempDir()
  1253  			tmpDir.Mkdir("k8s")
  1254  			tmpDir.Write("skaffold.yaml", test.config)
  1255  			tmpDir.Write("k8s/k8s-pod.yaml", test.manifest)
  1256  			tmpDir.Chdir()
  1257  
  1258  			args := []string{"--hydration-dir", hydrationDir}
  1259  
  1260  			skaffold.Render(args...).RunOrFail(t.T)
  1261  
  1262  			_, err := os.Stat(filepath.Join(tmpDir.Root(), hydrationDir))
  1263  
  1264  			if test.shouldCreateHydrationDir {
  1265  				t.CheckFalse(os.IsNotExist(err))
  1266  			} else {
  1267  				t.CheckTrue(os.IsNotExist(err))
  1268  			}
  1269  		})
  1270  	}
  1271  }
  1272  
  1273  func TestRenderParameterization(t *testing.T) {
  1274  	tests := []struct {
  1275  		description        string
  1276  		args               []string
  1277  		WithBuildArtifacts bool
  1278  		config             string
  1279  		input              map[string]string // file path => content
  1280  		expectedOut        string
  1281  	}{
  1282  		{
  1283  			description: "kubectl set manifest label with apply-setters",
  1284  			args:        []string{"--offline=true"},
  1285  			config: `apiVersion: skaffold/v4beta2
  1286  kind: Config
  1287  manifests:
  1288    rawYaml:
  1289      - k8s-pod.yaml
  1290    transform:
  1291      - name: apply-setters
  1292        configMap:
  1293          - "app1:from-apply-setters-1"
  1294  `,
  1295  			input: map[string]string{
  1296  				"k8s-pod.yaml": `apiVersion: v1
  1297  kind: Pod
  1298  metadata:
  1299    name: getting-started
  1300    labels:
  1301      a: hhhh # kpt-set: ${app1}
  1302  spec:
  1303    containers:
  1304    - name: getting-started
  1305      image: skaffold-example`,
  1306  			}, expectedOut: `apiVersion: v1
  1307  kind: Pod
  1308  metadata:
  1309    name: getting-started
  1310    labels:
  1311      a: from-apply-setters-1
  1312  spec:
  1313    containers:
  1314    - name: getting-started
  1315      image: skaffold-example
  1316  `,
  1317  		},
  1318  		{description: "kustomize set annotation with set-annotations transformer",
  1319  			args: []string{"--offline=true"},
  1320  			config: `apiVersion: skaffold/v4beta2
  1321  kind: Config
  1322  manifests:
  1323    kustomize:
  1324      paths:
  1325        - .
  1326    transform:
  1327      - name: set-annotations
  1328        configMap:
  1329          - "author:fake-author"`,
  1330  			input: map[string]string{
  1331  				"kustomization.yaml": `resources:
  1332    - deployment.yaml
  1333  patchesStrategicMerge:
  1334    - patch.yaml
  1335  `, "deployment.yaml": `apiVersion: apps/v1
  1336  kind: Deployment
  1337  metadata:
  1338    name: kustomize-test
  1339    labels:
  1340      app: kustomize-test
  1341  spec:
  1342    replicas: 1
  1343    selector:
  1344      matchLabels:
  1345        app: kustomize-test
  1346    template:
  1347      metadata:
  1348        labels:
  1349          app: kustomize-test
  1350      spec:
  1351        containers:
  1352          - name: kustomize-test
  1353            image: not/a/valid/image
  1354  `, "patch.yaml": `apiVersion: apps/v1
  1355  kind: Deployment
  1356  metadata:
  1357    name: kustomize-test
  1358  spec:
  1359    template:
  1360      spec:
  1361        containers:
  1362          - name: kustomize-test
  1363            image: index.docker.io/library/busybox
  1364            command:
  1365              - sleep
  1366              - "3600"
  1367  `},
  1368  			expectedOut: `apiVersion: apps/v1
  1369  kind: Deployment
  1370  metadata:
  1371    annotations:
  1372      author: fake-author
  1373    labels:
  1374      app: kustomize-test
  1375    name: kustomize-test
  1376  spec:
  1377    replicas: 1
  1378    selector:
  1379      matchLabels:
  1380        app: kustomize-test
  1381    template:
  1382      metadata:
  1383        annotations:
  1384          author: fake-author
  1385        labels:
  1386          app: kustomize-test
  1387      spec:
  1388        containers:
  1389          - command:
  1390              - sleep
  1391              - "3600"
  1392            image: index.docker.io/library/busybox
  1393            name: kustomize-test
  1394  `},
  1395  		{
  1396  			description: "kustomize/overlay parameterization with --set flag",
  1397  			args:        []string{"--offline", "--set", "env2=222a", "--set", "app1=111a"},
  1398  			config: `apiVersion: skaffold/v4beta2
  1399  kind: Config
  1400  metadata:
  1401    name: getting-started-kustomize
  1402  manifests:
  1403    kustomize:
  1404      paths:
  1405      - overlays/dev
  1406  `, input: map[string]string{"base/kustomization.yaml": `
  1407  apiVersion: kustomize.config.k8s.io/v1beta1
  1408  kind: Kustomization
  1409  
  1410  resources:
  1411    - deployment.yaml
  1412  `, "base/deployment.yaml": `apiVersion: apps/v1
  1413  kind: Deployment
  1414  metadata:
  1415    name: skaffold-kustomize
  1416    labels:
  1417      app: skaffold-kustomize # from-param: ${app1}
  1418  spec:
  1419    selector:
  1420      matchLabels:
  1421        app: skaffold-kustomize
  1422    template:
  1423      metadata:
  1424        labels:
  1425          app: skaffold-kustomize
  1426      spec:
  1427        containers:
  1428        - name: skaffold-kustomize
  1429          image: skaffold-kustomize
  1430  `, "overlays/dev/kustomization.yaml": `apiVersion: kustomize.config.k8s.io/v1beta1
  1431  kind: Kustomization
  1432  
  1433  # namespace: dev
  1434  nameSuffix: -dev
  1435  
  1436  patchesStrategicMerge:
  1437  - deployment.yaml
  1438  
  1439  resources:
  1440  - ../../base
  1441  `, "overlays/dev/deployment.yaml": `apiVersion: apps/v1
  1442  kind: Deployment
  1443  metadata:
  1444    name: skaffold-kustomize
  1445    labels:
  1446      env: dev # from-param: ${env2}
  1447  `}, expectedOut: `
  1448  apiVersion: apps/v1
  1449  kind: Deployment
  1450  metadata:
  1451    labels:
  1452      app: 111a
  1453      env: 222a
  1454    name: skaffold-kustomize-dev
  1455  spec:
  1456    selector:
  1457      matchLabels:
  1458        app: skaffold-kustomize
  1459    template:
  1460      metadata:
  1461        labels:
  1462          app: skaffold-kustomize
  1463      spec:
  1464        containers:
  1465        - image: skaffold-kustomize
  1466          name: skaffold-kustomize
  1467  `,
  1468  		},
  1469  		{
  1470  			description: "kustomize parameterization success with patches",
  1471  			args:        []string{"--offline", "--set", "app1=111a"},
  1472  			config: `apiVersion: skaffold/v4beta2
  1473  kind: Config
  1474  metadata:
  1475    name: getting-started-kustomize
  1476  manifests:
  1477    kustomize:
  1478      paths:
  1479      - base
  1480  `, input: map[string]string{"base/kustomization.yaml": `
  1481  apiVersion: kustomize.config.k8s.io/v1beta1
  1482  kind: Kustomization
  1483  patches:
  1484    - path: patch.yaml
  1485      target:
  1486        group: apps
  1487        version: v1
  1488        kind: Deployment
  1489        name: skaffold-kustomize
  1490  resources:
  1491    - deployment.yaml
  1492  `, "base/deployment.yaml": `apiVersion: apps/v1
  1493  kind: Deployment
  1494  metadata:
  1495    name: skaffold-kustomize
  1496    labels:
  1497      app: skaffold-kustomize # from-param: ${app1}
  1498  spec:
  1499    selector:
  1500      matchLabels:
  1501        app: skaffold-kustomize
  1502    template:
  1503      metadata:
  1504        labels:
  1505          app: skaffold-kustomize
  1506      spec:
  1507        containers:
  1508        - name: skaffold-kustomize
  1509          image: skaffold-kustomize
  1510  `, "base/patch.yaml": `
  1511  - op: add
  1512    path: /metadata/annotations/example.com
  1513    value: dummy
  1514  `}, expectedOut: `
  1515  apiVersion: apps/v1
  1516  kind: Deployment
  1517  metadata:
  1518    labels:
  1519      app: 111a
  1520    name: skaffold-kustomize
  1521    annotations:
  1522      example.com: dummy
  1523  spec:
  1524    selector:
  1525      matchLabels:
  1526        app: skaffold-kustomize
  1527    template:
  1528      metadata:
  1529        labels:
  1530          app: skaffold-kustomize
  1531      spec:
  1532        containers:
  1533        - image: skaffold-kustomize
  1534          name: skaffold-kustomize
  1535  `,
  1536  		},
  1537  		{description: "test set transformer values with value file",
  1538  			args: []string{"--offline=true", "--set-value-file", "values.env"},
  1539  			config: `
  1540  apiVersion: skaffold/v4beta2
  1541  kind: Config
  1542  manifests:
  1543    rawYaml:
  1544      - k8s-pod.yaml
  1545  `,
  1546  			input: map[string]string{
  1547  				"k8s-pod.yaml": `
  1548  apiVersion: v1
  1549  kind: Pod
  1550  metadata:
  1551    name: getting-started
  1552    labels:
  1553      a: hhhh # from-param: ${app1}
  1554  spec:
  1555    containers:
  1556      - name: getting-started
  1557        image: skaffold-example`,
  1558  				"values.env": `app1=from-file`,
  1559  			}, expectedOut: `apiVersion: v1
  1560  kind: Pod
  1561  metadata:
  1562    name: getting-started
  1563    labels:
  1564      a: from-file
  1565  spec:
  1566    containers:
  1567      - name: getting-started
  1568        image: skaffold-example
  1569  `,
  1570  		},
  1571  		{
  1572  			description: "test set transformer values with value file and value from command-line",
  1573  			args:        []string{"--offline=true", "--set-value-file", "values.env", "--set", "app2=from-command-line"},
  1574  			config: `
  1575  apiVersion: skaffold/v4beta2
  1576  kind: Config
  1577  manifests:
  1578    rawYaml:
  1579      - k8s-pod.yaml
  1580    transform:
  1581      - name: apply-setters
  1582        configMap:
  1583          - "app1:from-apply-setters-1"
  1584  `,
  1585  			input: map[string]string{
  1586  				"k8s-pod.yaml": `
  1587  apiVersion: v1
  1588  kind: Pod
  1589  metadata:
  1590    name: getting-started
  1591    labels:
  1592      a: hhhh # from-param: ${app1}
  1593      b: hhhh # from-param: ${app2}
  1594  spec:
  1595    containers:
  1596      - name: getting-started
  1597        image: skaffold-example`,
  1598  				"values.env": `app1=from-file`,
  1599  			}, expectedOut: `apiVersion: v1
  1600  kind: Pod
  1601  metadata:
  1602    name: getting-started
  1603    labels:
  1604      a: from-file
  1605      b: from-command-line
  1606  spec:
  1607    containers:
  1608      - name: getting-started
  1609        image: skaffold-example
  1610  `},
  1611  		{
  1612  			description: "test set transformer file values respect values from command-line",
  1613  			args:        []string{"--offline=true", "--set-value-file", "values.env", "--set", "app1=from-command-line"},
  1614  			config: `
  1615  apiVersion: skaffold/v4beta2
  1616  kind: Config
  1617  manifests:
  1618    rawYaml:
  1619      - k8s-pod.yaml
  1620    transform:
  1621      - name: apply-setters
  1622        configMap:
  1623          - "app1:from-apply-setters-1"
  1624  `,
  1625  			input: map[string]string{
  1626  				"k8s-pod.yaml": `
  1627  apiVersion: v1
  1628  kind: Pod
  1629  metadata:
  1630    name: getting-started
  1631    labels:
  1632      a: hhhh # from-param: ${app1}
  1633  spec:
  1634    containers:
  1635      - name: getting-started
  1636        image: skaffold-example`,
  1637  				"values.env": `app1=from-file`,
  1638  			}, expectedOut: `apiVersion: v1
  1639  kind: Pod
  1640  metadata:
  1641    name: getting-started
  1642    labels:
  1643      a: from-command-line
  1644  spec:
  1645    containers:
  1646      - name: getting-started
  1647        image: skaffold-example
  1648  `},
  1649  		{
  1650  			description: "test set param with helm native template(replicaCount)",
  1651  			args:        []string{"--offline=true", "--set", "replicaCount=5"},
  1652  			config: `
  1653  apiVersion: skaffold/v4beta2
  1654  kind: Config
  1655  manifests:
  1656    helm:
  1657      releases:
  1658        - name: skaffold-helm
  1659          chartPath: charts
  1660          namespace: helm-namespace
  1661  `,
  1662  			input: map[string]string{
  1663  				"charts/templates/deployments.yaml": `
  1664  apiVersion: apps/v1
  1665  kind: Deployment
  1666  metadata:
  1667    name: {{ .Chart.Name }}
  1668    namespace: {{ .Release.Namespace }}
  1669    labels:
  1670      app: {{ .Chart.Name }}
  1671  spec:
  1672    selector:
  1673      matchLabels:
  1674        app: {{ .Chart.Name }}
  1675    replicas: {{ .Values.replicaCount }}
  1676    template:
  1677      metadata:
  1678        labels:
  1679          app: {{ .Chart.Name }}
  1680      spec:
  1681        containers:
  1682        - name: {{ .Chart.Name }}
  1683          image: {{ .Values.image }}
  1684  `,
  1685  				"charts/Chart.yaml": `
  1686  apiVersion: v1
  1687  description: Skaffold example with Helm
  1688  name: skaffold-helm
  1689  version: 0.1.0
  1690  `,
  1691  				"charts/values.yaml": `
  1692  replicaCount: 2
  1693  image: skaffold-helm:latest
  1694  `,
  1695  			}, expectedOut: `apiVersion: apps/v1
  1696  kind: Deployment
  1697  metadata:
  1698    name: skaffold-helm
  1699    namespace: helm-namespace
  1700    labels:
  1701      app: skaffold-helm
  1702  spec:
  1703    selector:
  1704      matchLabels:
  1705        app: skaffold-helm
  1706    replicas: 5
  1707    template:
  1708      metadata:
  1709        labels:
  1710          app: skaffold-helm
  1711      spec:
  1712        containers:
  1713        - name: skaffold-helm
  1714          image: skaffold-helm:latest
  1715  `},
  1716  		{
  1717  			description:        "test set param with helm #from-param overrides native template(replicaCount) is comment templated field provided",
  1718  			args:               []string{"--offline=true", "--set", "replicaCount=5", "--set", "count=6"},
  1719  			WithBuildArtifacts: true,
  1720  			config: `
  1721  apiVersion: skaffold/v4beta2
  1722  kind: Config
  1723  manifests:
  1724    helm:
  1725      releases:
  1726        - name: skaffold-helm
  1727          chartPath: charts
  1728          namespace: helm-namespace
  1729  `,
  1730  			input: map[string]string{
  1731  				"charts/templates/deployments.yaml": `
  1732  apiVersion: apps/v1
  1733  kind: Deployment
  1734  metadata:
  1735    name: {{ .Chart.Name }}
  1736    namespace: {{ .Release.Namespace }}
  1737    labels:
  1738      app: {{ .Chart.Name }}
  1739  spec:
  1740    selector:
  1741      matchLabels:
  1742        app: {{ .Chart.Name }}
  1743    replicas: {{ .Values.replicaCount }} # from-param: ${count}
  1744    template:
  1745      metadata:
  1746        labels:
  1747          app: {{ .Chart.Name }}
  1748      spec:
  1749        containers:
  1750        - name: {{ .Chart.Name }}
  1751          image: {{ .Values.image }}
  1752  `,
  1753  				"charts/Chart.yaml": `
  1754  apiVersion: v1
  1755  description: Skaffold example with Helm
  1756  name: skaffold-helm
  1757  version: 0.1.0
  1758  `,
  1759  				"charts/values.yaml": `
  1760  replicaCount: 2
  1761  image: skaffold-helm:latest
  1762  `,
  1763  			}, expectedOut: `apiVersion: apps/v1
  1764  kind: Deployment
  1765  metadata:
  1766    name: skaffold-helm
  1767    namespace: helm-namespace
  1768    labels:
  1769      app: skaffold-helm
  1770  spec:
  1771    selector:
  1772      matchLabels:
  1773        app: skaffold-helm
  1774    replicas: 6
  1775    template:
  1776      metadata:
  1777        labels:
  1778          app: skaffold-helm
  1779      spec:
  1780        containers:
  1781        - name: skaffold-helm
  1782          image: skaffold-helm:latest
  1783  `},
  1784  		{
  1785  			description:        "test set param with helm #from-param has no effect on native template(replicaCount) when comment templated field value not provided",
  1786  			args:               []string{"--offline=true", "--set", "replicaCount=5"},
  1787  			WithBuildArtifacts: true,
  1788  			config: `
  1789  apiVersion: skaffold/v4beta2
  1790  kind: Config
  1791  manifests:
  1792    helm:
  1793      releases:
  1794        - name: skaffold-helm
  1795          chartPath: charts
  1796          namespace: helm-namespace
  1797  `,
  1798  			input: map[string]string{
  1799  				"charts/templates/deployments.yaml": `
  1800  apiVersion: apps/v1
  1801  kind: Deployment
  1802  metadata:
  1803    name: {{ .Chart.Name }}
  1804    namespace: {{ .Release.Namespace }}
  1805    labels:
  1806      app: {{ .Chart.Name }}
  1807  spec:
  1808    selector:
  1809      matchLabels:
  1810        app: {{ .Chart.Name }}
  1811    replicas: {{ .Values.replicaCount }} # from-param: ${count}
  1812    template:
  1813      metadata:
  1814        labels:
  1815          app: {{ .Chart.Name }}
  1816      spec:
  1817        containers:
  1818        - name: {{ .Chart.Name }}
  1819          image: {{ .Values.image }}
  1820  `,
  1821  				"charts/Chart.yaml": `
  1822  apiVersion: v1
  1823  description: Skaffold example with Helm
  1824  name: skaffold-helm
  1825  version: 0.1.0
  1826  `,
  1827  				"charts/values.yaml": `
  1828  replicaCount: 2
  1829  image: skaffold-helm:latest
  1830  `,
  1831  			}, expectedOut: `apiVersion: apps/v1
  1832  kind: Deployment
  1833  metadata:
  1834    name: skaffold-helm
  1835    namespace: helm-namespace
  1836    labels:
  1837      app: skaffold-helm
  1838  spec:
  1839    selector:
  1840      matchLabels:
  1841        app: skaffold-helm
  1842    replicas: 5
  1843    template:
  1844      metadata:
  1845        labels:
  1846          app: skaffold-helm
  1847      spec:
  1848        containers:
  1849        - name: skaffold-helm
  1850          image: skaffold-helm:latest
  1851  `},
  1852  		{
  1853  			description:        "test set param with helm #from-param, values are provided through file",
  1854  			args:               []string{"--offline=true", "--set-value-file", "values.env"},
  1855  			WithBuildArtifacts: true,
  1856  			config: `
  1857  apiVersion: skaffold/v4beta2
  1858  kind: Config
  1859  manifests:
  1860    helm:
  1861      releases:
  1862        - name: skaffold-helm
  1863          chartPath: charts
  1864          namespace: helm-namespace
  1865  `,
  1866  			input: map[string]string{
  1867  				"charts/templates/deployments.yaml": `
  1868  apiVersion: apps/v1
  1869  kind: Deployment
  1870  metadata:
  1871    name: {{ .Chart.Name }}
  1872    namespace: {{ .Release.Namespace }}
  1873    labels:
  1874      app: {{ .Chart.Name }}
  1875  spec:
  1876    selector:
  1877      matchLabels:
  1878        app: {{ .Chart.Name }}
  1879    replicas: {{ .Values.replicaCount }} # from-param: ${count}
  1880    template:
  1881      metadata:
  1882        labels:
  1883          app: {{ .Chart.Name }}
  1884      spec:
  1885        containers:
  1886        - name: {{ .Chart.Name }}
  1887          image: {{ .Values.image }}
  1888  `,
  1889  				"charts/Chart.yaml": `
  1890  apiVersion: v1
  1891  description: Skaffold example with Helm
  1892  name: skaffold-helm
  1893  version: 0.1.0
  1894  `,
  1895  				"charts/values.yaml": `
  1896  replicaCount: 2
  1897  image: skaffold-helm:latest
  1898  `,
  1899  				"values.env": `count=3`,
  1900  			}, expectedOut: `apiVersion: apps/v1
  1901  kind: Deployment
  1902  metadata:
  1903    name: skaffold-helm
  1904    namespace: helm-namespace
  1905    labels:
  1906      app: skaffold-helm
  1907  spec:
  1908    selector:
  1909      matchLabels:
  1910        app: skaffold-helm
  1911    replicas: 3
  1912    template:
  1913      metadata:
  1914        labels:
  1915          app: skaffold-helm
  1916      spec:
  1917        containers:
  1918        - name: skaffold-helm
  1919          image: skaffold-helm:latest
  1920  `},
  1921  	}
  1922  
  1923  	for _, test := range tests {
  1924  		testutil.Run(t, test.description, func(t *testutil.T) {
  1925  			MarkIntegrationTest(t.T, CanRunWithoutGcp)
  1926  			tmpDir := t.NewTempDir()
  1927  			tmpDir.Write("skaffold.yaml", test.config)
  1928  
  1929  			for filePath, content := range test.input {
  1930  				tmpDir.Write(filePath, content)
  1931  			}
  1932  
  1933  			if test.WithBuildArtifacts {
  1934  				dir, _ := os.Getwd()
  1935  				test.args = append(test.args, "--build-artifacts="+filepath.Join(dir, "testdata/render/build-output.json"))
  1936  			}
  1937  
  1938  			tmpDir.Chdir()
  1939  			output := skaffold.Render(test.args...).RunOrFailOutput(t.T)
  1940  
  1941  			t.CheckDeepEqual(test.expectedOut, string(output), testutil.YamlObj(t.T))
  1942  		})
  1943  	}
  1944  }
  1945  
  1946  func TestRenderWithTagFlag(t *testing.T) {
  1947  	MarkIntegrationTest(t, CanRunWithoutGcp)
  1948  
  1949  	tests := []struct {
  1950  		description    string
  1951  		projectDir     string
  1952  		expectedOutput string
  1953  		namespaceFlag  string
  1954  	}{
  1955  		{
  1956  			description: "tag flag in a single module project",
  1957  			projectDir:  "testdata/getting-started",
  1958  			expectedOutput: `apiVersion: v1
  1959  kind: Pod
  1960  metadata:
  1961    name: getting-started
  1962  spec:
  1963    containers:
  1964    - image: gcr.io/k8s-skaffold/skaffold-example:customtag
  1965      name: getting-started
  1966  `,
  1967  		},
  1968  		{
  1969  			description: "tag flag in a multi module project",
  1970  			projectDir:  "testdata/multi-config-pods",
  1971  			expectedOutput: `apiVersion: v1
  1972  kind: Pod
  1973  metadata:
  1974    name: module1
  1975  spec:
  1976    containers:
  1977    - image: gcr.io/k8s-skaffold/multi-config-module1:customtag
  1978      name: module1
  1979  ---
  1980  apiVersion: v1
  1981  kind: Pod
  1982  metadata:
  1983    name: module2
  1984  spec:
  1985    containers:
  1986    - image: gcr.io/k8s-skaffold/multi-config-module2:customtag
  1987      name: module2
  1988  `,
  1989  		},
  1990  		{
  1991  			description:   "tag flag, with namespace flag, in a single module project",
  1992  			projectDir:    "testdata/getting-started",
  1993  			namespaceFlag: "mynamespace",
  1994  			expectedOutput: `apiVersion: v1
  1995  kind: Pod
  1996  metadata:
  1997    name: getting-started
  1998    namespace: mynamespace
  1999  spec:
  2000    containers:
  2001    - image: gcr.io/k8s-skaffold/skaffold-example:customtag
  2002      name: getting-started
  2003  `,
  2004  		},
  2005  		{
  2006  			description:   "tag flag, with namespace flag, in a multi module project",
  2007  			projectDir:    "testdata/multi-config-pods",
  2008  			namespaceFlag: "mynamespace",
  2009  			expectedOutput: `apiVersion: v1
  2010  kind: Pod
  2011  metadata:
  2012    name: module1
  2013    namespace: mynamespace
  2014  spec:
  2015    containers:
  2016    - image: gcr.io/k8s-skaffold/multi-config-module1:customtag
  2017      name: module1
  2018  ---
  2019  apiVersion: v1
  2020  kind: Pod
  2021  metadata:
  2022    name: module2
  2023    namespace: mynamespace
  2024  spec:
  2025    containers:
  2026    - image: gcr.io/k8s-skaffold/multi-config-module2:customtag
  2027      name: module2
  2028  `,
  2029  		},
  2030  	}
  2031  
  2032  	for _, test := range tests {
  2033  		testutil.Run(t, test.description, func(t *testutil.T) {
  2034  			args := []string{"--tag", "customtag", "--default-repo", "gcr.io/k8s-skaffold"}
  2035  
  2036  			if test.namespaceFlag != "" {
  2037  				args = append(args, "--namespace", test.namespaceFlag)
  2038  			}
  2039  
  2040  			output := skaffold.Render(args...).InDir(test.projectDir).RunOrFailOutput(t.T)
  2041  			t.CheckDeepEqual(string(output), test.expectedOutput, testutil.YamlObj(t.T))
  2042  		})
  2043  	}
  2044  }
  2045  
  2046  func TestRenderWithPostRenderHook(t *testing.T) {
  2047  	MarkIntegrationTest(t, CanRunWithoutGcp)
  2048  
  2049  	tests := []struct {
  2050  		description    string
  2051  		projectDir     string
  2052  		expectedOutput string
  2053  		expectedStderr string
  2054  		args           []string
  2055  	}{
  2056  		{
  2057  			description: "a single module project, one hook with change",
  2058  			projectDir:  "testdata/post-render-hooks",
  2059  			args:        []string{"-m", "m1", "-p", "change1", "-t", "customtag"},
  2060  			expectedOutput: `apiVersion: v1
  2061  kind: Pod
  2062  metadata:
  2063    name: module1
  2064    labels:
  2065      app1: after-change-1
  2066      app2: before-change-2
  2067           
  2068  spec:
  2069    containers:
  2070    - image: us-central1-docker.pkg.dev/k8s-skaffold/testing/multi-config-module1:customtag
  2071      name: module1
  2072  `,
  2073  		},
  2074  		{
  2075  			description: "a single module project, two hook with change",
  2076  			projectDir:  "testdata/post-render-hooks",
  2077  			args:        []string{"-m", "m1", "-p", "two-changes", "-t", "customtag"},
  2078  			expectedOutput: `apiVersion: v1
  2079  kind: Pod
  2080  metadata:
  2081    name: module1
  2082    labels:
  2083      app1: after-change-1
  2084      app2: after-change-2
  2085  spec:
  2086    containers:
  2087    - image: us-central1-docker.pkg.dev/k8s-skaffold/testing/multi-config-module1:customtag
  2088      name: module1
  2089  `,
  2090  		},
  2091  		{
  2092  			description: "a single module project, two hooks, one with change, one not",
  2093  			projectDir:  "testdata/post-render-hooks",
  2094  			args:        []string{"-m", "m1", "-p", "one-change-one-not", "-t", "customtag"},
  2095  			expectedOutput: `apiVersion: v1
  2096  kind: Pod
  2097  metadata:
  2098    name: module1
  2099    labels:
  2100      app1: before-change-1
  2101      app2: after-change-2
  2102  spec:
  2103    containers:
  2104    - image: us-central1-docker.pkg.dev/k8s-skaffold/testing/multi-config-module1:customtag
  2105      name: module1
  2106  `,
  2107  		},
  2108  		{
  2109  			description: "multi-module project, two hooks, two changes",
  2110  			projectDir:  "testdata/post-render-hooks",
  2111  			args:        []string{"-m", "m1,m2", "-p", "change1", "-t", "customtag"},
  2112  			expectedOutput: `apiVersion: v1
  2113  kind: Pod
  2114  metadata:
  2115    labels:
  2116      app1: after-change-1
  2117      app2: before-change-2
  2118    name: module1
  2119  spec:
  2120    containers:
  2121      - image: us-central1-docker.pkg.dev/k8s-skaffold/testing/multi-config-module1:customtag
  2122        name: module1
  2123  ---
  2124  apiVersion: v1
  2125  kind: Pod
  2126  metadata:
  2127    labels:
  2128      app1: before-change-1
  2129    name: module2
  2130  spec:
  2131    containers:
  2132      - image: us-central1-docker.pkg.dev/k8s-skaffold/testing/multi-config-module2:customtag
  2133        name: module2
  2134  `,
  2135  		},
  2136  		{
  2137  			description: "multi-module project, one pipeline with two hooks have changes, one pipeline has no changes",
  2138  			projectDir:  "testdata/post-render-hooks",
  2139  			args:        []string{"-m", "m1,m2", "-p", "change1,nochange2", "-t", "customtag"},
  2140  			expectedOutput: `apiVersion: v1
  2141  kind: Pod
  2142  metadata:
  2143    labels:
  2144      app1: after-change-1
  2145      app2: before-change-2
  2146    name: module1
  2147  spec:
  2148    containers:
  2149      - image: us-central1-docker.pkg.dev/k8s-skaffold/testing/multi-config-module1:customtag
  2150        name: module1
  2151  ---
  2152  apiVersion: v1
  2153  kind: Pod
  2154  metadata:
  2155    labels:
  2156      app1: before-change-1
  2157    name: module2
  2158  spec:
  2159    containers:
  2160      - image: us-central1-docker.pkg.dev/k8s-skaffold/testing/multi-config-module2:customtag
  2161        name: module2
  2162  `,
  2163  		},
  2164  		{
  2165  			description: "single module project, one hook with changes, other without changes and with output",
  2166  			projectDir:  "testdata/post-render-hooks",
  2167  			args:        []string{"-m", "m1", "-p", "one-change-two-without-change-but-with-output", "-t", "customtag"},
  2168  			expectedOutput: `apiVersion: v1
  2169  kind: Pod
  2170  metadata:
  2171    labels:
  2172      app1: before-change-1
  2173      app2: after-change-2
  2174    name: module1
  2175  spec:
  2176    containers:
  2177      - image: us-central1-docker.pkg.dev/k8s-skaffold/testing/multi-config-module1:customtag
  2178        name: module1
  2179  `,
  2180  			expectedStderr: `Starting post-render hooks...
  2181  running post-render hook 1
  2182  running post-render hook 2
  2183  Completed post-render hooks`,
  2184  		},
  2185  	}
  2186  
  2187  	for _, test := range tests {
  2188  		testutil.Run(t, test.description, func(t *testutil.T) {
  2189  			stdout := new(bytes.Buffer)
  2190  			stderr := new(bytes.Buffer)
  2191  			skaffold.Render(test.args...).InDir(test.projectDir).RunWithStdoutAndStderrOrFail(t.T, stdout, stderr)
  2192  			t.CheckDeepEqual(test.expectedOutput, stdout.String(), testutil.YamlObj(t.T))
  2193  			if test.expectedStderr != "" {
  2194  				t.CheckMatches(test.expectedStderr, stderr.String())
  2195  			}
  2196  		})
  2197  	}
  2198  }
  2199  
  2200  func TestKptRender(t *testing.T) {
  2201  	tests := []struct {
  2202  		description string
  2203  		args        []string
  2204  		config      string
  2205  		input       map[string]string // file path => content
  2206  		expectedOut string
  2207  	}{
  2208  		{
  2209  			description: "simple kpt render",
  2210  			config: `apiVersion: skaffold/v4beta2
  2211  kind: Config
  2212  metadata:
  2213    name: getting-started-kustomize
  2214  manifests:
  2215    kpt:
  2216      - apply-simple
  2217  `, input: map[string]string{"apply-simple/Kptfile": `apiVersion: kpt.dev/v1
  2218  kind: Kptfile
  2219  metadata:
  2220    name: apply-setters-simple
  2221  upstream:
  2222    type: git
  2223    git:
  2224      repo: https://github.com/GoogleContainerTools/kpt-functions-catalog
  2225      directory: /examples/apply-setters-simple
  2226      ref: apply-setters/v0.2.0
  2227    updateStrategy: resource-merge
  2228  upstreamLock:
  2229    type: git
  2230    git:
  2231      repo: https://github.com/GoogleContainerTools/kpt-functions-catalog
  2232      directory: /examples/apply-setters-simple
  2233      ref: apply-setters/v0.2.0
  2234      commit: 9b6ce80e355a53727d21b2b336f8da55e760e20ca
  2235  pipeline:
  2236    mutators:
  2237      - image: gcr.io/kpt-fn/apply-setters:v0.2
  2238        configMap:
  2239          nginx-replicas: 3
  2240          tag: 1.16.2
  2241  `, "apply-simple/resources.yaml": `apiVersion: apps/v1
  2242  kind: Deployment
  2243  metadata:
  2244    name: my-nginx
  2245  spec:
  2246    replicas: 4 # kpt-set: ${nginx-replicas}
  2247    selector:
  2248      matchLabels:
  2249        app: nginx
  2250    template:
  2251      metadata:
  2252        labels:
  2253          app: nginx
  2254      spec:
  2255        containers:
  2256          - name: nginx
  2257            image: "nginx:1.16.1" # kpt-set: nginx:${tag}
  2258            ports:
  2259              - protocol: TCP
  2260                containerPort: 80`},
  2261  			expectedOut: `apiVersion: apps/v1
  2262  kind: Deployment
  2263  metadata:
  2264    name: my-nginx
  2265  spec:
  2266    replicas: 3
  2267    selector:
  2268      matchLabels:
  2269        app: nginx
  2270    template:
  2271      metadata:
  2272        labels:
  2273          app: nginx
  2274      spec:
  2275        containers:
  2276          - name: nginx
  2277            image: "nginx:1.16.2"
  2278            ports:
  2279              - protocol: TCP
  2280                containerPort: 80
  2281  `},
  2282  		{
  2283  			description: "kpt render with data config file",
  2284  			config: `apiVersion: skaffold/v4beta2
  2285  kind: Config
  2286  metadata:
  2287    name: getting-started-kustomize
  2288  manifests:
  2289    kpt:
  2290      - set-annotations
  2291  `,
  2292  			input: map[string]string{"set-annotations/Kptfile": `apiVersion: kpt.dev/v1
  2293  kind: Kptfile
  2294  metadata:
  2295    name: example
  2296  pipeline:
  2297    mutators:
  2298      - image: gcr.io/kpt-fn/set-annotations:v0.1.4
  2299        configPath: fn-config.yaml`,
  2300  				"set-annotations/fn-config.yaml": `apiVersion: fn.kpt.dev/v1alpha1
  2301  kind: SetAnnotations
  2302  metadata: # kpt-merge: /my-func-config
  2303    name: my-func-config
  2304    annotations:
  2305      config.kubernetes.io/local-config: "true"
  2306      internal.kpt.dev/upstream-identifier: 'fn.kpt.dev|SetAnnotations|default|my-func-config'
  2307  annotations:
  2308    color: orange
  2309    fruit: apple
  2310  `,
  2311  				"set-annotations/resources.yaml": `apiVersion: apps/v1
  2312  kind: Deployment
  2313  metadata:
  2314    name: my-nginx
  2315  spec:
  2316    replicas: 3 # kpt-set: ${nginx-replicas}
  2317    selector:
  2318      matchLabels:
  2319        app: nginx
  2320    template:
  2321      metadata:
  2322        labels:
  2323          app: nginx
  2324      spec:
  2325        containers:
  2326          - name: nginx
  2327            image: "nginx:1.16.1" # kpt-set: nginx:${tag}
  2328            ports:
  2329              - protocol: TCP
  2330                containerPort: 80`},
  2331  			expectedOut: `apiVersion: apps/v1
  2332  kind: Deployment
  2333  metadata:
  2334    name: my-nginx
  2335    annotations: 
  2336      color: orange
  2337      fruit: apple
  2338  spec:
  2339    replicas: 3
  2340    selector:
  2341      matchLabels:
  2342        app: nginx
  2343    template:
  2344      metadata:
  2345        annotations: 
  2346          color: orange
  2347          fruit: apple
  2348        labels:
  2349          app: nginx
  2350      spec:
  2351        containers:
  2352          - name: nginx
  2353            image: "nginx:1.16.1"
  2354            ports:
  2355              - protocol: TCP
  2356                containerPort: 80
  2357  `},
  2358  		{
  2359  			description: "simple kpt render with namespace flag",
  2360  			args:        []string{"--namespace", "mynamespace"},
  2361  			config: `apiVersion: skaffold/v4beta2
  2362  kind: Config
  2363  metadata:
  2364    name: getting-started-kustomize
  2365  manifests:
  2366    kpt:
  2367    - apply-simple
  2368  `,
  2369  			input: map[string]string{"apply-simple/Kptfile": `apiVersion: kpt.dev/v1
  2370  kind: Kptfile
  2371  metadata:
  2372    name: apply-setters-simple
  2373  upstream:
  2374    type: git
  2375    git:
  2376      repo: https://github.com/GoogleContainerTools/kpt-functions-catalog
  2377      directory: /examples/apply-setters-simple
  2378      ref: apply-setters/v0.2.0
  2379    updateStrategy: resource-merge
  2380  upstreamLock:
  2381    type: git
  2382    git:
  2383      repo: https://github.com/GoogleContainerTools/kpt-functions-catalog
  2384      directory: /examples/apply-setters-simple
  2385      ref: apply-setters/v0.2.0
  2386      commit: 9b6ce80e355a53727d21b2b336f8da55e760e20ca
  2387  pipeline:
  2388    mutators:
  2389      - image: gcr.io/kpt-fn/apply-setters:v0.2
  2390        configMap:
  2391          nginx-replicas: 3
  2392          tag: 1.16.2
  2393  `,
  2394  				"apply-simple/resources.yaml": `apiVersion: apps/v1
  2395  kind: Deployment
  2396  metadata:
  2397    name: my-nginx
  2398  spec:
  2399    replicas: 4 # kpt-set: ${nginx-replicas}
  2400    selector:
  2401      matchLabels:
  2402        app: nginx
  2403    template:
  2404      metadata:
  2405        labels:
  2406          app: nginx
  2407      spec:
  2408        containers:
  2409          - name: nginx
  2410            image: "nginx:1.16.1" # kpt-set: nginx:${tag}
  2411            ports:
  2412              - protocol: TCP
  2413                containerPort: 80
  2414  `},
  2415  			expectedOut: `apiVersion: apps/v1
  2416  kind: Deployment
  2417  metadata:
  2418    name: my-nginx
  2419    namespace: mynamespace
  2420  spec:
  2421    replicas: 3
  2422    selector:
  2423      matchLabels:
  2424        app: nginx
  2425    template:
  2426      metadata:
  2427        labels:
  2428          app: nginx
  2429      spec:
  2430        containers:
  2431          - name: nginx
  2432            image: "nginx:1.16.2"
  2433            ports:
  2434              - protocol: TCP
  2435                containerPort: 80
  2436  `},
  2437  	}
  2438  
  2439  	for _, test := range tests {
  2440  		testutil.Run(t, test.description, func(t *testutil.T) {
  2441  			MarkIntegrationTest(t.T, CanRunWithoutGcp)
  2442  			tmpDir := t.NewTempDir()
  2443  			tmpDir.Write("skaffold.yaml", test.config)
  2444  
  2445  			for filePath, content := range test.input {
  2446  				tmpDir.Write(filePath, content)
  2447  			}
  2448  
  2449  			tmpDir.Chdir()
  2450  			output := skaffold.Render(test.args...).RunOrFailOutput(t.T)
  2451  			var out map[string]any
  2452  			var ex map[string]any
  2453  			err := yaml.Unmarshal(output, &out)
  2454  			if err != nil {
  2455  				return
  2456  			}
  2457  			err = yaml.Unmarshal([]byte(test.expectedOut), &ex)
  2458  			if err != nil {
  2459  				return
  2460  			}
  2461  
  2462  			t.CheckDeepEqual(ex, out)
  2463  		})
  2464  	}
  2465  }
  2466  
  2467  func TestHelmRenderWithImagesFlag(t *testing.T) {
  2468  	tests := []struct {
  2469  		description  string
  2470  		dir          string
  2471  		args         []string
  2472  		builds       []graph.Artifact
  2473  		helmReleases []latest.HelmRelease
  2474  		expectedOut  string
  2475  	}{
  2476  		{
  2477  			description: "verify --images flag work with helm render",
  2478  			dir:         "testdata/helm-render",
  2479  			args:        []string{"--profile=helm-render", "--images=us-central1-docker.pkg.dev/k8s-skaffold/testing/skaffold-helm:latest@sha256:3e8981b13fadcbb5f4d42d00fdf52a9de128feea5280f0a1f7fb542cf31f1a06"},
  2480  			expectedOut: `apiVersion: v1
  2481  kind: Service
  2482  metadata:
  2483    labels:
  2484      app: skaffold-helm
  2485      chart: skaffold-helm-0.1.0
  2486      heritage: Helm
  2487      release: skaffold-helm
  2488      skaffold.dev/run-id: phony-run-id
  2489    name: skaffold-helm-skaffold-helm
  2490  spec:
  2491    ports:
  2492    - name: nginx
  2493      port: 80
  2494      protocol: TCP
  2495      targetPort: 80
  2496    selector:
  2497      app: skaffold-helm
  2498      release: skaffold-helm
  2499    type: ClusterIP
  2500  ---
  2501  apiVersion: apps/v1
  2502  kind: Deployment
  2503  metadata:
  2504    labels:
  2505      app: skaffold-helm
  2506      chart: skaffold-helm-0.1.0
  2507      heritage: Helm
  2508      release: skaffold-helm
  2509      skaffold.dev/run-id: phony-run-id
  2510    name: skaffold-helm
  2511  spec:
  2512    replicas: 1
  2513    selector:
  2514      matchLabels:
  2515        app: skaffold-helm
  2516        release: skaffold-helm
  2517    template:
  2518      metadata:
  2519        labels:
  2520          app: skaffold-helm
  2521          release: skaffold-helm
  2522          skaffold.dev/run-id: phony-run-id
  2523      spec:
  2524        containers:
  2525        - image: us-central1-docker.pkg.dev/k8s-skaffold/testing/skaffold-helm:latest@sha256:3e8981b13fadcbb5f4d42d00fdf52a9de128feea5280f0a1f7fb542cf31f1a06
  2526          imagePullPolicy: always
  2527          name: skaffold-helm
  2528          ports:
  2529          - containerPort: 80
  2530          resources: {}
  2531  ---
  2532  apiVersion: networking.k8s.io/v1
  2533  kind: Ingress
  2534  metadata:
  2535    annotations: null
  2536    labels:
  2537      app: skaffold-helm
  2538      chart: skaffold-helm-0.1.0
  2539      heritage: Helm
  2540      release: skaffold-helm
  2541    name: skaffold-helm-skaffold-helm
  2542  spec:
  2543    rules:
  2544    - http:
  2545        paths:
  2546        - backend:
  2547            service:
  2548              name: skaffold-helm-skaffold-helm
  2549              port:
  2550                number: 80
  2551          path: /
  2552          pathType: ImplementationSpecific
  2553  `,
  2554  		},
  2555  	}
  2556  	for _, test := range tests {
  2557  		t.Run(test.description, func(t *testing.T) {
  2558  			MarkIntegrationTest(t, CanRunWithoutGcp)
  2559  			out := skaffold.Render(append([]string{"--default-repo=", "--label=skaffold.dev/run-id=phony-run-id"}, test.args...)...).InDir(test.dir).RunOrFailOutput(t)
  2560  
  2561  			testutil.CheckDeepEqual(t, test.expectedOut, string(out), testutil.YamlObj(t))
  2562  		})
  2563  	}
  2564  }
  2565  
  2566  func TestRenderRemoteKustomize(t *testing.T) {
  2567  	testutil.Run(t, "render remote kustomize resource success", func(t *testutil.T) {
  2568  		MarkIntegrationTest(t.T, CanRunWithoutGcp)
  2569  		skaffold.Render().InDir("testdata/kustomize/remote").RunOrFail(t.T)
  2570  	})
  2571  }