You've already forked sap-jenkins-library
							
							
				mirror of
				https://github.com/SAP/jenkins-library.git
				synced 2025-10-30 23:57:50 +02:00 
			
		
		
		
	feat(cnbBuild) containerImageName will be defaulted if possible (#3437)
Co-authored-by: Ralf Pannemans <ralf.pannemans@sap.com> Co-authored-by: Johannes Dillmann <j.dillmann@sap.com> Co-authored-by: Sumit Kulhadia <sumit.kulhadia@sap.com>
This commit is contained in:
		| @@ -6,7 +6,6 @@ import ( | ||||
| 	"os" | ||||
| 	"path" | ||||
| 	"path/filepath" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/SAP/jenkins-library/pkg/certutils" | ||||
| @@ -268,6 +267,7 @@ func runCnbBuild(config *cnbBuildOptions, telemetryData *telemetry.CustomData, u | ||||
| 		return errors.Wrap(err, "failed to check if project descriptor exists") | ||||
| 	} | ||||
|  | ||||
| 	var projectID string | ||||
| 	if projDescExists { | ||||
| 		descriptor, err := project.ParseDescriptor(config.ProjectDescriptor, utils, httpClient) | ||||
| 		if err != nil { | ||||
| @@ -288,8 +288,19 @@ func runCnbBuild(config *cnbBuildOptions, telemetryData *telemetry.CustomData, u | ||||
| 		if descriptor.Include != nil { | ||||
| 			include = descriptor.Include | ||||
| 		} | ||||
|  | ||||
| 		projectID = descriptor.ProjectID | ||||
| 	} | ||||
|  | ||||
| 	targetImage, err := cnbutils.GetTargetImage(config.ContainerRegistryURL, config.ContainerImageName, config.ContainerImageTag, projectID, GeneralConfig.EnvRootPath) | ||||
| 	if err != nil { | ||||
| 		log.SetErrorCategory(log.ErrorConfiguration) | ||||
| 		return errors.Wrap(err, "failed to retrieve target image configuration") | ||||
| 	} | ||||
|  | ||||
| 	commonPipelineEnvironment.container.registryURL = fmt.Sprintf("%s://%s", targetImage.ContainerRegistry.Scheme, targetImage.ContainerRegistry.Host) | ||||
| 	commonPipelineEnvironment.container.imageNameTag = fmt.Sprintf("%v:%v", targetImage.ContainerImageName, targetImage.ContainerImageTag) | ||||
|  | ||||
| 	if config.BuildEnvVars != nil && len(config.BuildEnvVars) > 0 { | ||||
| 		log.Entry().Infof("Setting custom environment variables: '%v'", config.BuildEnvVars) | ||||
| 		err = cnbutils.CreateEnvFiles(utils, platformPath, config.BuildEnvVars) | ||||
| @@ -322,7 +333,7 @@ func runCnbBuild(config *cnbBuildOptions, telemetryData *telemetry.CustomData, u | ||||
| 	} | ||||
|  | ||||
| 	var source string | ||||
| 	if len(config.Path) > 0 { | ||||
| 	if config.Path != "" { | ||||
| 		source = config.Path | ||||
| 	} else { | ||||
| 		source = pwd | ||||
| @@ -386,28 +397,6 @@ func runCnbBuild(config *cnbBuildOptions, telemetryData *telemetry.CustomData, u | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if len(config.ContainerRegistryURL) == 0 || len(config.ContainerImageName) == 0 || len(config.ContainerImageTag) == 0 { | ||||
| 		log.SetErrorCategory(log.ErrorConfiguration) | ||||
| 		return errors.New("containerRegistryUrl, containerImageName and containerImageTag must be present") | ||||
| 	} | ||||
|  | ||||
| 	var containerRegistry string | ||||
| 	if matched, _ := regexp.MatchString("^(http|https)://.*", config.ContainerRegistryURL); matched { | ||||
| 		containerRegistry, err = docker.ContainerRegistryFromURL(config.ContainerRegistryURL) | ||||
| 		if err != nil { | ||||
| 			log.SetErrorCategory(log.ErrorConfiguration) | ||||
| 			return errors.Wrapf(err, "failed to read containerRegistryUrl %s", config.ContainerRegistryURL) | ||||
| 		} | ||||
| 		commonPipelineEnvironment.container.registryURL = config.ContainerRegistryURL | ||||
| 	} else { | ||||
| 		containerRegistry = config.ContainerRegistryURL | ||||
| 		commonPipelineEnvironment.container.registryURL = fmt.Sprintf("https://%v", config.ContainerRegistryURL) | ||||
| 	} | ||||
|  | ||||
| 	containerImage := path.Join(containerRegistry, config.ContainerImageName) | ||||
| 	containerImageTag := strings.ReplaceAll(config.ContainerImageTag, "+", "-") | ||||
| 	commonPipelineEnvironment.container.imageNameTag = fmt.Sprintf("%v:%v", config.ContainerImageName, containerImageTag) | ||||
|  | ||||
| 	if len(config.CustomTLSCertificateLinks) > 0 { | ||||
| 		caCertificates := "/tmp/ca-certificates.crt" | ||||
| 		_, err := utils.Copy("/etc/ssl/certs/ca-certificates.crt", caCertificates) | ||||
| @@ -433,6 +422,7 @@ func runCnbBuild(config *cnbBuildOptions, telemetryData *telemetry.CustomData, u | ||||
| 		"-platform", platformPath, | ||||
| 	} | ||||
|  | ||||
| 	containerImage := path.Join(targetImage.ContainerRegistry.Host, targetImage.ContainerImageName) | ||||
| 	for _, tag := range config.AdditionalTags { | ||||
| 		target := fmt.Sprintf("%s:%s", containerImage, tag) | ||||
| 		if !piperutils.ContainsString(creatorArgs, target) { | ||||
| @@ -440,7 +430,7 @@ func runCnbBuild(config *cnbBuildOptions, telemetryData *telemetry.CustomData, u | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	creatorArgs = append(creatorArgs, fmt.Sprintf("%s:%s", containerImage, containerImageTag)) | ||||
| 	creatorArgs = append(creatorArgs, fmt.Sprintf("%s:%s", containerImage, targetImage.ContainerImageTag)) | ||||
| 	err = utils.RunExecutable(creatorPath, creatorArgs...) | ||||
| 	if err != nil { | ||||
| 		log.SetErrorCategory(log.ErrorBuild) | ||||
|   | ||||
| @@ -154,7 +154,7 @@ func CnbBuildCommand() *cobra.Command { | ||||
| } | ||||
|  | ||||
| func addCnbBuildFlags(cmd *cobra.Command, stepConfig *cnbBuildOptions) { | ||||
| 	cmd.Flags().StringVar(&stepConfig.ContainerImageName, "containerImageName", os.Getenv("PIPER_containerImageName"), "Name of the container which will be built") | ||||
| 	cmd.Flags().StringVar(&stepConfig.ContainerImageName, "containerImageName", os.Getenv("PIPER_containerImageName"), "Name of the container which will be built\n`cnbBuild` step will try to identify a containerImageName using the following precedence:\n  1. `containerImageName` parameter.\n  2. `project.id` field of a `project.toml` file.\n  3. `git/repository` parameter of the `commonPipelineEnvironment`.\nIf none of the above was found - an error will be raised.\n") | ||||
| 	cmd.Flags().StringVar(&stepConfig.ContainerImageTag, "containerImageTag", os.Getenv("PIPER_containerImageTag"), "Tag of the container which will be built") | ||||
| 	cmd.Flags().StringVar(&stepConfig.ContainerRegistryURL, "containerRegistryUrl", os.Getenv("PIPER_containerRegistryUrl"), "Container registry where the image should be pushed to") | ||||
| 	cmd.Flags().StringSliceVar(&stepConfig.Buildpacks, "buildpacks", []string{}, "List of custom buildpacks to use in the form of '$HOSTNAME/$REPO[:$TAG]'.") | ||||
| @@ -165,7 +165,6 @@ func addCnbBuildFlags(cmd *cobra.Command, stepConfig *cnbBuildOptions) { | ||||
| 	cmd.Flags().StringSliceVar(&stepConfig.CustomTLSCertificateLinks, "customTlsCertificateLinks", []string{}, "List containing download links of custom TLS certificates. This is required to ensure trusted connections to registries with custom certificates.") | ||||
| 	cmd.Flags().StringSliceVar(&stepConfig.AdditionalTags, "additionalTags", []string{}, "List of tags which will be pushed to the registry (additionally to the provided `containerImageTag`), e.g. \"latest\".") | ||||
|  | ||||
| 	cmd.MarkFlagRequired("containerImageName") | ||||
| 	cmd.MarkFlagRequired("containerImageTag") | ||||
| 	cmd.MarkFlagRequired("containerRegistryUrl") | ||||
| } | ||||
| @@ -189,7 +188,7 @@ func cnbBuildMetadata() config.StepData { | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:        "string", | ||||
| 						Mandatory:   true, | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{{Name: "dockerImageName"}}, | ||||
| 						Default:     os.Getenv("PIPER_containerImageName"), | ||||
| 					}, | ||||
|   | ||||
| @@ -13,6 +13,8 @@ import ( | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| const imageRegistry = "some-registry" | ||||
|  | ||||
| func newCnbBuildTestsUtils() cnbutils.MockUtils { | ||||
| 	utils := cnbutils.MockUtils{ | ||||
| 		ExecMockRunner: &mock.ExecMockRunner{}, | ||||
| @@ -35,14 +37,73 @@ func assertLifecycleCalls(t *testing.T, runner *mock.ExecMockRunner) { | ||||
| func TestRunCnbBuild(t *testing.T) { | ||||
| 	t.Parallel() | ||||
|  | ||||
| 	t.Run("success case (registry with https)", func(t *testing.T) { | ||||
| 	t.Run("preferes direct configuration", func(t *testing.T) { | ||||
| 		t.Parallel() | ||||
| 		commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{} | ||||
| 		registry := "some-registry" | ||||
| 		config := cnbBuildOptions{ | ||||
| 			ContainerImageName:   "my-image", | ||||
| 			ContainerImageTag:    "0.0.1", | ||||
| 			ContainerRegistryURL: fmt.Sprintf("https://%s", registry), | ||||
| 			ContainerRegistryURL: fmt.Sprintf("https://%s", imageRegistry), | ||||
| 			DockerConfigJSON:     "/path/to/config.json", | ||||
| 		} | ||||
|  | ||||
| 		projectToml := `[project] | ||||
| 		id = "io.buildpacks.my-app" | ||||
| 		` | ||||
|  | ||||
| 		utils := newCnbBuildTestsUtils() | ||||
| 		utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`)) | ||||
| 		utils.FilesMock.AddFile("project.toml", []byte(projectToml)) | ||||
| 		addBuilderFiles(&utils) | ||||
|  | ||||
| 		err := runCnbBuild(&config, &telemetry.CustomData{}, &utils, &commonPipelineEnvironment, &piperhttp.Client{}) | ||||
|  | ||||
| 		assert.NoError(t, err) | ||||
| 		runner := utils.ExecMockRunner | ||||
| 		assert.Contains(t, runner.Env, "CNB_REGISTRY_AUTH={\"my-registry\":\"Basic dXNlcjpwYXNz\"}") | ||||
| 		assertLifecycleCalls(t, runner) | ||||
| 		assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:%s", imageRegistry, config.ContainerImageName, config.ContainerImageTag)) | ||||
| 		assert.Equal(t, config.ContainerRegistryURL, commonPipelineEnvironment.container.registryURL) | ||||
| 		assert.Equal(t, "my-image:0.0.1", commonPipelineEnvironment.container.imageNameTag) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("preferes project descriptor", func(t *testing.T) { | ||||
| 		t.Parallel() | ||||
| 		commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{} | ||||
| 		config := cnbBuildOptions{ | ||||
| 			ContainerImageTag:    "0.0.1", | ||||
| 			ContainerRegistryURL: fmt.Sprintf("https://%s", imageRegistry), | ||||
| 			DockerConfigJSON:     "/path/to/config.json", | ||||
| 			ProjectDescriptor:    "project.toml", | ||||
| 		} | ||||
|  | ||||
| 		projectToml := `[project] | ||||
| 		id = "io.buildpacks.my-app" | ||||
| 		` | ||||
|  | ||||
| 		utils := newCnbBuildTestsUtils() | ||||
| 		utils.FilesMock.AddFile(config.DockerConfigJSON, []byte(`{"auths":{"my-registry":{"auth":"dXNlcjpwYXNz"}}}`)) | ||||
| 		utils.FilesMock.AddFile("project.toml", []byte(projectToml)) | ||||
| 		addBuilderFiles(&utils) | ||||
|  | ||||
| 		err := runCnbBuild(&config, &telemetry.CustomData{}, &utils, &commonPipelineEnvironment, &piperhttp.Client{}) | ||||
|  | ||||
| 		assert.NoError(t, err) | ||||
| 		runner := utils.ExecMockRunner | ||||
| 		assert.Contains(t, runner.Env, "CNB_REGISTRY_AUTH={\"my-registry\":\"Basic dXNlcjpwYXNz\"}") | ||||
| 		assertLifecycleCalls(t, runner) | ||||
| 		assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:%s", imageRegistry, "io-buildpacks-my-app", config.ContainerImageTag)) | ||||
| 		assert.Equal(t, config.ContainerRegistryURL, commonPipelineEnvironment.container.registryURL) | ||||
| 		assert.Equal(t, "io-buildpacks-my-app:0.0.1", commonPipelineEnvironment.container.imageNameTag) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("success case (registry with https)", func(t *testing.T) { | ||||
| 		t.Parallel() | ||||
| 		commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{} | ||||
| 		config := cnbBuildOptions{ | ||||
| 			ContainerImageName:   "my-image", | ||||
| 			ContainerImageTag:    "0.0.1", | ||||
| 			ContainerRegistryURL: fmt.Sprintf("https://%s", imageRegistry), | ||||
| 			DockerConfigJSON:     "/path/to/config.json", | ||||
| 		} | ||||
|  | ||||
| @@ -56,19 +117,18 @@ func TestRunCnbBuild(t *testing.T) { | ||||
| 		runner := utils.ExecMockRunner | ||||
| 		assert.Contains(t, runner.Env, "CNB_REGISTRY_AUTH={\"my-registry\":\"Basic dXNlcjpwYXNz\"}") | ||||
| 		assertLifecycleCalls(t, runner) | ||||
| 		assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:%s", registry, config.ContainerImageName, config.ContainerImageTag)) | ||||
| 		assert.Equal(t, fmt.Sprintf("https://%s", registry), commonPipelineEnvironment.container.registryURL) | ||||
| 		assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:%s", imageRegistry, config.ContainerImageName, config.ContainerImageTag)) | ||||
| 		assert.Equal(t, config.ContainerRegistryURL, commonPipelineEnvironment.container.registryURL) | ||||
| 		assert.Equal(t, "my-image:0.0.1", commonPipelineEnvironment.container.imageNameTag) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("success case (registry without https)", func(t *testing.T) { | ||||
| 		t.Parallel() | ||||
| 		registry := "some-registry" | ||||
| 		commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{} | ||||
| 		config := cnbBuildOptions{ | ||||
| 			ContainerImageName:   "my-image", | ||||
| 			ContainerImageTag:    "0.0.1", | ||||
| 			ContainerRegistryURL: registry, | ||||
| 			ContainerRegistryURL: imageRegistry, | ||||
| 			DockerConfigJSON:     "/path/to/config.json", | ||||
| 		} | ||||
|  | ||||
| @@ -82,19 +142,18 @@ func TestRunCnbBuild(t *testing.T) { | ||||
| 		runner := utils.ExecMockRunner | ||||
| 		assert.Contains(t, runner.Env, "CNB_REGISTRY_AUTH={\"my-registry\":\"Basic dXNlcjpwYXNz\"}") | ||||
| 		assertLifecycleCalls(t, runner) | ||||
| 		assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:%s", registry, config.ContainerImageName, config.ContainerImageTag)) | ||||
| 		assert.Equal(t, fmt.Sprintf("https://%s", registry), commonPipelineEnvironment.container.registryURL) | ||||
| 		assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:%s", config.ContainerRegistryURL, config.ContainerImageName, config.ContainerImageTag)) | ||||
| 		assert.Equal(t, fmt.Sprintf("https://%s", config.ContainerRegistryURL), commonPipelineEnvironment.container.registryURL) | ||||
| 		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() | ||||
| 		registry := "some-registry" | ||||
| 		commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{} | ||||
| 		config := cnbBuildOptions{ | ||||
| 			ContainerImageName:   "my-image", | ||||
| 			ContainerImageTag:    "0.0.1", | ||||
| 			ContainerRegistryURL: registry, | ||||
| 			ContainerRegistryURL: imageRegistry, | ||||
| 			DockerConfigJSON:     "/path/to/test.json", | ||||
| 			Buildpacks:           []string{"test"}, | ||||
| 			BuildEnvVars: map[string]interface{}{ | ||||
| @@ -115,8 +174,8 @@ func TestRunCnbBuild(t *testing.T) { | ||||
| 		assert.Equal(t, creatorPath, runner.Calls[0].Exec) | ||||
| 		assert.Contains(t, runner.Calls[0].Params, "/tmp/buildpacks") | ||||
| 		assert.Contains(t, runner.Calls[0].Params, "/tmp/buildpacks/order.toml") | ||||
| 		assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:%s", registry, config.ContainerImageName, config.ContainerImageTag)) | ||||
| 		assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:latest", registry, config.ContainerImageName)) | ||||
| 		assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:%s", config.ContainerRegistryURL, config.ContainerImageName, config.ContainerImageTag)) | ||||
| 		assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:latest", config.ContainerRegistryURL, config.ContainerImageName)) | ||||
|  | ||||
| 		initialFileExists, _ := utils.FileExists("/path/to/test.json") | ||||
| 		renamedFileExists, _ := utils.FileExists("/path/to/config.json") | ||||
| @@ -162,17 +221,16 @@ func TestRunCnbBuild(t *testing.T) { | ||||
| 		assert.Contains(t, runner.Env, "CNB_REGISTRY_AUTH={\"my-registry\":\"Basic dXNlcjpwYXNz\"}") | ||||
| 		assert.Contains(t, runner.Env, fmt.Sprintf("SSL_CERT_FILE=%s", caCertsTmpFile)) | ||||
| 		assertLifecycleCalls(t, runner) | ||||
| 		assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:%s", registry, config.ContainerImageName, config.ContainerImageTag)) | ||||
| 		assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:%s", config.ContainerRegistryURL, config.ContainerImageName, config.ContainerImageTag)) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("success case (additionalTags)", func(t *testing.T) { | ||||
| 		t.Parallel() | ||||
| 		commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{} | ||||
| 		registry := "some-registry" | ||||
| 		config := cnbBuildOptions{ | ||||
| 			ContainerImageName:   "my-image", | ||||
| 			ContainerImageTag:    "3.1.5", | ||||
| 			ContainerRegistryURL: registry, | ||||
| 			ContainerRegistryURL: imageRegistry, | ||||
| 			DockerConfigJSON:     "/path/to/config.json", | ||||
| 			AdditionalTags:       []string{"3", "3.1", "3.1", "3.1.5"}, | ||||
| 		} | ||||
| @@ -186,10 +244,10 @@ func TestRunCnbBuild(t *testing.T) { | ||||
|  | ||||
| 		runner := utils.ExecMockRunner | ||||
| 		assertLifecycleCalls(t, runner) | ||||
| 		assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:%s", registry, config.ContainerImageName, config.ContainerImageTag)) | ||||
| 		assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:3", registry, config.ContainerImageName)) | ||||
| 		assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:3.1", registry, config.ContainerImageName)) | ||||
| 		assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:3.1.5", registry, config.ContainerImageName)) | ||||
| 		assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:%s", config.ContainerRegistryURL, config.ContainerImageName, config.ContainerImageTag)) | ||||
| 		assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:3", config.ContainerRegistryURL, config.ContainerImageName)) | ||||
| 		assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:3.1", config.ContainerRegistryURL, config.ContainerImageName)) | ||||
| 		assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:3.1.5", config.ContainerRegistryURL, config.ContainerImageName)) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("pom.xml exists (symlink for the target folder)", func(t *testing.T) { | ||||
| @@ -197,7 +255,7 @@ func TestRunCnbBuild(t *testing.T) { | ||||
| 		config := cnbBuildOptions{ | ||||
| 			ContainerImageName:   "my-image", | ||||
| 			ContainerImageTag:    "3.1.5", | ||||
| 			ContainerRegistryURL: "some-registry", | ||||
| 			ContainerRegistryURL: imageRegistry, | ||||
| 			DockerConfigJSON:     "/path/to/config.json", | ||||
| 		} | ||||
|  | ||||
| @@ -222,7 +280,7 @@ func TestRunCnbBuild(t *testing.T) { | ||||
| 		config := cnbBuildOptions{ | ||||
| 			ContainerImageName:   "my-image", | ||||
| 			ContainerImageTag:    "3.1.5", | ||||
| 			ContainerRegistryURL: "some-registry", | ||||
| 			ContainerRegistryURL: imageRegistry, | ||||
| 			DockerConfigJSON:     "/path/to/config.json", | ||||
| 		} | ||||
|  | ||||
| @@ -245,8 +303,10 @@ func TestRunCnbBuild(t *testing.T) { | ||||
| 		t.Parallel() | ||||
| 		commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{} | ||||
| 		config := cnbBuildOptions{ | ||||
| 			ContainerImageName: "my-image", | ||||
| 			DockerConfigJSON:   "/path/to/config.json", | ||||
| 			ContainerImageTag:    "0.0.1", | ||||
| 			ContainerRegistryURL: imageRegistry, | ||||
| 			ContainerImageName:   "my-image", | ||||
| 			DockerConfigJSON:     "/path/to/config.json", | ||||
| 		} | ||||
|  | ||||
| 		utils := newCnbBuildTestsUtils() | ||||
| @@ -261,8 +321,10 @@ func TestRunCnbBuild(t *testing.T) { | ||||
| 		t.Parallel() | ||||
| 		commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{} | ||||
| 		config := cnbBuildOptions{ | ||||
| 			ContainerImageName: "my-image", | ||||
| 			DockerConfigJSON:   "not-there/config.json", | ||||
| 			ContainerImageTag:    "0.0.1", | ||||
| 			ContainerRegistryURL: imageRegistry, | ||||
| 			ContainerImageName:   "my-image", | ||||
| 			DockerConfigJSON:     "not-there/config.json", | ||||
| 		} | ||||
|  | ||||
| 		utils := newCnbBuildTestsUtils() | ||||
| @@ -276,8 +338,10 @@ func TestRunCnbBuild(t *testing.T) { | ||||
| 		t.Parallel() | ||||
| 		commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{} | ||||
| 		config := cnbBuildOptions{ | ||||
| 			ContainerImageName: "my-image", | ||||
| 			DockerConfigJSON:   "not-there", | ||||
| 			ContainerImageTag:    "0.0.1", | ||||
| 			ContainerRegistryURL: imageRegistry, | ||||
| 			ContainerImageName:   "my-image", | ||||
| 			DockerConfigJSON:     "not-there", | ||||
| 		} | ||||
|  | ||||
| 		utils := newCnbBuildTestsUtils() | ||||
| @@ -301,11 +365,10 @@ func TestRunCnbBuild(t *testing.T) { | ||||
| 	t.Run("error case: builder image does not contain tls certificates", func(t *testing.T) { | ||||
| 		t.Parallel() | ||||
| 		commonPipelineEnvironment := cnbBuildCommonPipelineEnvironment{} | ||||
| 		registry := "some-registry" | ||||
| 		config := cnbBuildOptions{ | ||||
| 			ContainerImageName:        "my-image", | ||||
| 			ContainerImageTag:         "0.0.1", | ||||
| 			ContainerRegistryURL:      registry, | ||||
| 			ContainerRegistryURL:      imageRegistry, | ||||
| 			DockerConfigJSON:          "/path/to/config.json", | ||||
| 			Buildpacks:                []string{"test"}, | ||||
| 			CustomTLSCertificateLinks: []string{"http://example.com/certs.pem"}, | ||||
|   | ||||
| @@ -1,3 +1,4 @@ | ||||
| //go:build !windows | ||||
| // +build !windows | ||||
|  | ||||
| package cmd | ||||
|   | ||||
| @@ -36,8 +36,13 @@ type build struct { | ||||
| 	Env        []envVar    `toml:"env"` | ||||
| } | ||||
|  | ||||
| type project struct { | ||||
| 	ID string `toml:"id"` | ||||
| } | ||||
|  | ||||
| type projectDescriptor struct { | ||||
| 	Build    build                  `toml:"build"` | ||||
| 	Project  project                `toml:"project"` | ||||
| 	Metadata map[string]interface{} `toml:"metadata"` | ||||
| } | ||||
|  | ||||
| @@ -46,26 +51,27 @@ type Descriptor struct { | ||||
| 	Include    *ignore.GitIgnore | ||||
| 	EnvVars    map[string]interface{} | ||||
| 	Buildpacks []string | ||||
| 	ProjectID  string | ||||
| } | ||||
|  | ||||
| func ParseDescriptor(descriptorPath string, utils cnbutils.BuildUtils, httpClient piperhttp.Sender) (Descriptor, error) { | ||||
| 	descriptor := Descriptor{} | ||||
| func ParseDescriptor(descriptorPath string, utils cnbutils.BuildUtils, httpClient piperhttp.Sender) (*Descriptor, error) { | ||||
| 	descriptor := &Descriptor{} | ||||
|  | ||||
| 	descriptorContent, err := utils.FileRead(descriptorPath) | ||||
| 	if err != nil { | ||||
| 		return Descriptor{}, err | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	rawDescriptor := projectDescriptor{} | ||||
| 	err = toml.Unmarshal(descriptorContent, &rawDescriptor) | ||||
| 	if err != nil { | ||||
| 		return Descriptor{}, err | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	if rawDescriptor.Build.Buildpacks != nil && len(rawDescriptor.Build.Buildpacks) > 0 { | ||||
| 		buildpacksImg, err := rawDescriptor.Build.searchBuildpacks(httpClient) | ||||
| 		if err != nil { | ||||
| 			return Descriptor{}, err | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		descriptor.Buildpacks = buildpacksImg | ||||
| @@ -76,7 +82,7 @@ func ParseDescriptor(descriptorPath string, utils cnbutils.BuildUtils, httpClien | ||||
| 	} | ||||
|  | ||||
| 	if len(rawDescriptor.Build.Exclude) > 0 && len(rawDescriptor.Build.Include) > 0 { | ||||
| 		return Descriptor{}, errors.New("project descriptor options 'exclude' and 'include' are mutually exclusive") | ||||
| 		return nil, errors.New("project descriptor options 'exclude' and 'include' are mutually exclusive") | ||||
| 	} | ||||
|  | ||||
| 	if len(rawDescriptor.Build.Exclude) > 0 { | ||||
| @@ -87,6 +93,10 @@ func ParseDescriptor(descriptorPath string, utils cnbutils.BuildUtils, httpClien | ||||
| 		descriptor.Include = ignore.CompileIgnoreLines(rawDescriptor.Build.Include...) | ||||
| 	} | ||||
|  | ||||
| 	if len(rawDescriptor.Project.ID) > 0 { | ||||
| 		descriptor.ProjectID = rawDescriptor.Project.ID | ||||
| 	} | ||||
|  | ||||
| 	return descriptor, nil | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -65,6 +65,8 @@ id = "paketo-buildpacks/nodejs" | ||||
| 		assert.Equal(t, descriptor.EnvVars["VAR1"], "VAL1") | ||||
| 		assert.Equal(t, descriptor.EnvVars["VAR2"], "VAL2") | ||||
|  | ||||
| 		assert.Equal(t, descriptor.ProjectID, "io.buildpacks.my-app") | ||||
|  | ||||
| 		assert.Contains(t, descriptor.Buildpacks, "index.docker.io/test-java@5.9.1") | ||||
| 		assert.Contains(t, descriptor.Buildpacks, "index.docker.io/test-nodejs@1.1.1") | ||||
|  | ||||
|   | ||||
							
								
								
									
										54
									
								
								pkg/cnbutils/target_image.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								pkg/cnbutils/target_image.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | ||||
| package cnbutils | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"net/url" | ||||
| 	"path/filepath" | ||||
| 	"regexp" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/SAP/jenkins-library/pkg/piperenv" | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
|  | ||||
| type TargetImage struct { | ||||
| 	ContainerImageName string | ||||
| 	ContainerImageTag  string | ||||
| 	ContainerRegistry  *url.URL | ||||
| } | ||||
|  | ||||
| func GetTargetImage(imageRegistry, imageName, imageTag, projectID, envRootPath string) (*TargetImage, error) { | ||||
| 	if imageRegistry == "" || imageTag == "" { | ||||
| 		return nil, errors.New("containerRegistryUrl and containerImageTag must be present") | ||||
| 	} | ||||
|  | ||||
| 	targetImage := &TargetImage{ | ||||
| 		ContainerImageTag: strings.ReplaceAll(imageTag, "+", "-"), | ||||
| 	} | ||||
|  | ||||
| 	if matched, _ := regexp.MatchString("^(http|https)://.*", imageRegistry); !matched { | ||||
| 		imageRegistry = fmt.Sprintf("https://%s", imageRegistry) | ||||
| 	} | ||||
|  | ||||
| 	url, err := url.ParseRequestURI(imageRegistry) | ||||
| 	if err != nil { | ||||
| 		return nil, errors.Wrap(err, "invalid registry url") | ||||
| 	} | ||||
| 	targetImage.ContainerRegistry = url | ||||
|  | ||||
| 	cpePath := filepath.Join(envRootPath, "commonPipelineEnvironment") | ||||
| 	gitRepository := piperenv.GetResourceParameter(cpePath, "git", "repository") | ||||
|  | ||||
| 	if imageName != "" { | ||||
| 		targetImage.ContainerImageName = imageName | ||||
| 	} else if projectID != "" { | ||||
| 		name := strings.ReplaceAll(projectID, ".", "-") | ||||
| 		targetImage.ContainerImageName = name | ||||
| 	} else if gitRepository != "" { | ||||
| 		targetImage.ContainerImageName = strings.ReplaceAll(gitRepository, ".", "-") | ||||
| 	} else { | ||||
| 		return nil, errors.New("failed to derive default for image name") | ||||
| 	} | ||||
|  | ||||
| 	return targetImage, nil | ||||
| } | ||||
							
								
								
									
										83
									
								
								pkg/cnbutils/target_image_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								pkg/cnbutils/target_image_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,83 @@ | ||||
| package cnbutils_test | ||||
|  | ||||
| import ( | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/SAP/jenkins-library/pkg/cnbutils" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| func TestGetImageName(t *testing.T) { | ||||
| 	t.Parallel() | ||||
|  | ||||
| 	t.Run("Registry without protocol will add https", func(t *testing.T) { | ||||
| 		t.Parallel() | ||||
|  | ||||
| 		targetImage, err := cnbutils.GetTargetImage("registry", "image", "tag", "", "") | ||||
|  | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, "https", targetImage.ContainerRegistry.Scheme) | ||||
| 		assert.Equal(t, "registry", targetImage.ContainerRegistry.Host) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("Registry with protocol will keep it", func(t *testing.T) { | ||||
| 		t.Parallel() | ||||
|  | ||||
| 		targetImage, err := cnbutils.GetTargetImage("http://registry", "image", "tag", "", "") | ||||
|  | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, "http", targetImage.ContainerRegistry.Scheme) | ||||
| 		assert.Equal(t, "registry", targetImage.ContainerRegistry.Host) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("Image name is taken from the configuration", func(t *testing.T) { | ||||
| 		t.Parallel() | ||||
|  | ||||
| 		targetImage, err := cnbutils.GetTargetImage("http://registry", "image", "tag", "", "") | ||||
|  | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, "image", targetImage.ContainerImageName) | ||||
| 		assert.Equal(t, "tag", targetImage.ContainerImageTag) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("Image name is taken from project.toml", func(t *testing.T) { | ||||
| 		t.Parallel() | ||||
|  | ||||
| 		targetImage, err := cnbutils.GetTargetImage("http://registry", "", "tag", "project-id.0", "") | ||||
|  | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, "project-id-0", targetImage.ContainerImageName) | ||||
| 		assert.Equal(t, "tag", targetImage.ContainerImageTag) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("Image name is taken from git repo", func(t *testing.T) { | ||||
| 		t.Parallel() | ||||
|  | ||||
| 		tmpdir, err := ioutil.TempDir("", "cpe") | ||||
| 		assert.NoError(t, err) | ||||
| 		defer os.RemoveAll(tmpdir) | ||||
|  | ||||
| 		err = os.MkdirAll(filepath.Join(tmpdir, "commonPipelineEnvironment", "git"), os.ModePerm) | ||||
| 		assert.NoError(t, err) | ||||
|  | ||||
| 		err = ioutil.WriteFile(filepath.Join(tmpdir, "commonPipelineEnvironment", "git", "repository"), []byte("repo-name"), os.ModePerm) | ||||
| 		assert.NoError(t, err) | ||||
|  | ||||
| 		targetImage, err := cnbutils.GetTargetImage("http://registry", "", "tag", "", tmpdir) | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, "repo-name", targetImage.ContainerImageName) | ||||
| 		assert.Equal(t, "tag", targetImage.ContainerImageTag) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("throws an error if unable to find image name", func(t *testing.T) { | ||||
| 		t.Parallel() | ||||
|  | ||||
| 		_, err := cnbutils.GetTargetImage("http://registry", "", "tag", "", "") | ||||
|  | ||||
| 		assert.Error(t, err) | ||||
| 		assert.Equal(t, "failed to derive default for image name", err.Error()) | ||||
| 	}) | ||||
| } | ||||
| @@ -38,8 +38,13 @@ spec: | ||||
|         aliases: | ||||
|           - name: dockerImageName | ||||
|         type: string | ||||
|         mandatory: true | ||||
|         description: Name of the container which will be built | ||||
|         description: | | ||||
|           Name of the container which will be built | ||||
|           `cnbBuild` step will try to identify a containerImageName using the following precedence: | ||||
|             1. `containerImageName` parameter. | ||||
|             2. `project.id` field of a `project.toml` file. | ||||
|             3. `git/repository` parameter of the `commonPipelineEnvironment`. | ||||
|           If none of the above was found - an error will be raised. | ||||
|         scope: | ||||
|           - GENERAL | ||||
|           - PARAMETERS | ||||
|   | ||||
		Reference in New Issue
	
	Block a user