From 28fa2608dd4fa67f9d5029f6df85ec4d67d3a367 Mon Sep 17 00:00:00 2001 From: Philipp Stehle Date: Thu, 1 Feb 2024 13:53:13 +0100 Subject: [PATCH] cnbBuild: allow expansion of `buildEnvVars` (#4802) * cnbBuild: allow expansion of `buildEnvVars` * Update resources/metadata/cnbBuild.yaml Co-authored-by: Ralf Pannemans --------- Co-authored-by: Ralf Pannemans --- cmd/cnbBuild.go | 17 +++++++++++++++++ cmd/cnbBuild_generated.go | 11 +++++++++++ cmd/cnbBuild_test.go | 14 ++++++++++---- resources/metadata/cnbBuild.yaml | 15 +++++++++++++++ 4 files changed, 53 insertions(+), 4 deletions(-) diff --git a/cmd/cnbBuild.go b/cmd/cnbBuild.go index 3fbd2b9784..0a541d1104 100644 --- a/cmd/cnbBuild.go +++ b/cmd/cnbBuild.go @@ -455,6 +455,10 @@ func runCnbBuild(config *cnbBuildOptions, telemetry *buildpacks.Telemetry, image } commonPipelineEnvironment.container.imageNames = append(commonPipelineEnvironment.container.imageNames, imageNameAlias) + if config.ExpandBuildEnvVars { + config.BuildEnvVars = expandEnvVars(config.BuildEnvVars) + } + if config.BuildEnvVars != nil && len(config.BuildEnvVars) > 0 { log.Entry().Infof("Setting custom environment variables: '%v'", config.BuildEnvVars) imageSummary.AddEnv(config.BuildEnvVars) @@ -619,6 +623,19 @@ func runCnbBuild(config *cnbBuildOptions, telemetry *buildpacks.Telemetry, image return nil } +func expandEnvVars(envVars map[string]any) map[string]any { + expandedEnvVars := map[string]any{} + for key, value := range envVars { + valueString, valueIsString := value.(string) + if valueIsString { + expandedEnvVars[key] = os.ExpandEnv(valueString) + } else { + expandedEnvVars[key] = value + } + } + return expandedEnvVars +} + func createInitialTelemetrySegment(config *cnbBuildOptions, utils cnbutils.BuildUtils) *buildpacks.Segment { telemetrySegment := buildpacks.NewSegment() projectPath, _, _ := config.resolvePath(utils) // ignore error here, telemetry problems should not fail the build diff --git a/cmd/cnbBuild_generated.go b/cmd/cnbBuild_generated.go index 5ff450c700..bc827ac03b 100644 --- a/cmd/cnbBuild_generated.go +++ b/cmd/cnbBuild_generated.go @@ -30,6 +30,7 @@ type cnbBuildOptions struct { PreBuildpacks []string `json:"preBuildpacks,omitempty"` PostBuildpacks []string `json:"postBuildpacks,omitempty"` BuildEnvVars map[string]interface{} `json:"buildEnvVars,omitempty"` + ExpandBuildEnvVars bool `json:"expandBuildEnvVars,omitempty"` Path string `json:"path,omitempty"` ProjectDescriptor string `json:"projectDescriptor,omitempty"` DockerConfigJSON string `json:"dockerConfigJSON,omitempty"` @@ -238,6 +239,7 @@ func addCnbBuildFlags(cmd *cobra.Command, stepConfig *cnbBuildOptions) { cmd.Flags().StringSliceVar(&stepConfig.PreBuildpacks, "preBuildpacks", []string{}, "Buildpacks to prepend to the groups in the builder's order.") cmd.Flags().StringSliceVar(&stepConfig.PostBuildpacks, "postBuildpacks", []string{}, "Buildpacks to append to the groups in the builder's order.") + cmd.Flags().BoolVar(&stepConfig.ExpandBuildEnvVars, "expandBuildEnvVars", false, "Expand environment variables used in `buildEnvVars`.\nExample:\n```yaml\nexpandBuildEnvVars: true\nbuildEnvVars:\n foo: ${BAR}\n```\n") cmd.Flags().StringVar(&stepConfig.Path, "path", os.Getenv("PIPER_path"), "Glob that should either point to a directory with your sources or one artifact in zip format.\nThis property determines the input to the buildpack.\n") cmd.Flags().StringVar(&stepConfig.ProjectDescriptor, "projectDescriptor", `project.toml`, "Relative path to the project.toml file.\nSee [buildpacks.io](https://buildpacks.io/docs/reference/config/project-descriptor/) for the reference.\nParameters passed to the cnbBuild step will take precedence over the parameters set in the project.toml file, except the `env` block.\nEnvironment variables declared in a project descriptor file, will be merged with the `buildEnvVars` property, with the `buildEnvVars` having a precedence.\n\n*Note*: The project descriptor path should be relative to what is set in the [path](#path) property. If the `path` property is pointing to a zip archive (e.g. jar file), project descriptor path will be relative to the root of the workspace.\n\n*Note*: Inline buildpacks (see [specification](https://buildpacks.io/docs/reference/config/project-descriptor/#build-_table-optional_)) are not supported yet.\n") cmd.Flags().StringVar(&stepConfig.DockerConfigJSON, "dockerConfigJSON", os.Getenv("PIPER_dockerConfigJSON"), "Path to the file `.docker/config.json` - this is typically provided by your CI/CD system. You can find more details about the Docker credentials in the [Docker documentation](https://docs.docker.com/engine/reference/commandline/login/).") @@ -371,6 +373,15 @@ func cnbBuildMetadata() config.StepData { Mandatory: false, Aliases: []config.Alias{}, }, + { + Name: "expandBuildEnvVars", + ResourceRef: []config.ResourceReference{}, + Scope: []string{"PARAMETERS", "STAGES", "STEPS"}, + Type: "bool", + Mandatory: false, + Aliases: []config.Alias{}, + Default: false, + }, { Name: "path", ResourceRef: []config.ResourceReference{}, diff --git a/cmd/cnbBuild_test.go b/cmd/cnbBuild_test.go index cf62cc5bc7..e9eb9713c3 100644 --- a/cmd/cnbBuild_test.go +++ b/cmd/cnbBuild_test.go @@ -238,16 +238,17 @@ func TestRunCnbBuild(t *testing.T) { assert.Equal(t, "my-image:0.0.1", commonPipelineEnvironment.container.imageNameTag) }) - t.Run("success case (custom buildpacks and custom env variables, renaming docker conf file, additional tag)", func(t *testing.T) { - t.Parallel() + t.Run("success case (custom buildpacks and custom env variables with expand, renaming docker conf file, additional tag)", func(t *testing.T) { + t.Setenv("BAR", "BAZZ") config := cnbBuildOptions{ ContainerImageName: "my-image", ContainerImageTag: "0.0.1", ContainerRegistryURL: imageRegistry, DockerConfigJSON: "/path/to/test.json", Buildpacks: []string{"test"}, + ExpandBuildEnvVars: true, BuildEnvVars: map[string]interface{}{ - "FOO": "BAR", + "FOO": "${BAR}", }, AdditionalTags: []string{"latest"}, } @@ -269,6 +270,8 @@ func TestRunCnbBuild(t *testing.T) { copiedFileExists, _ := utils.FileExists("/tmp/config.json") assert.True(t, copiedFileExists) + + assetBuildEnv(t, utils, "FOO", "BAZZ") }) t.Run("success case (custom buildpacks, pre and post buildpacks and custom env variables, renaming docker conf file, additional tag)", func(t *testing.T) { @@ -281,8 +284,9 @@ func TestRunCnbBuild(t *testing.T) { PreBuildpacks: []string{"pre-test"}, PostBuildpacks: []string{"post-test"}, Buildpacks: []string{"test"}, + ExpandBuildEnvVars: false, BuildEnvVars: map[string]interface{}{ - "FOO": "BAR", + "FOO": "${BAR}", }, AdditionalTags: []string{"latest"}, } @@ -304,6 +308,8 @@ func TestRunCnbBuild(t *testing.T) { copiedFileExists, _ := utils.FileExists("/tmp/config.json") assert.True(t, copiedFileExists) + + assetBuildEnv(t, utils, "FOO", "${BAR}") }) t.Run("success case (custom pre and post buildpacks and custom env variables, renaming docker conf file, additional tag)", func(t *testing.T) { diff --git a/resources/metadata/cnbBuild.yaml b/resources/metadata/cnbBuild.yaml index 947ebf5278..d6e7427f94 100644 --- a/resources/metadata/cnbBuild.yaml +++ b/resources/metadata/cnbBuild.yaml @@ -138,6 +138,21 @@ spec: - PARAMETERS - STAGES - STEPS + - name: expandBuildEnvVars + type: "bool" + default: false + description: | + Expand environment variables used in `buildEnvVars`. + Example: + ```yaml + expandBuildEnvVars: true + buildEnvVars: + foo: ${BAR} + ``` + scope: + - PARAMETERS + - STAGES + - STEPS - name: path type: string description: |