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): write image digests to the CPE (#3602)
Co-authored-by: Johannes Dillmann <j.dillmann@sap.com>
This commit is contained in:
		| @@ -19,6 +19,7 @@ import ( | ||||
| 	piperhttp "github.com/SAP/jenkins-library/pkg/http" | ||||
| 	"github.com/SAP/jenkins-library/pkg/log" | ||||
| 	"github.com/SAP/jenkins-library/pkg/piperutils" | ||||
|  | ||||
| 	"github.com/SAP/jenkins-library/pkg/telemetry" | ||||
| 	"github.com/imdario/mergo" | ||||
| 	"github.com/mitchellh/mapstructure" | ||||
| @@ -554,6 +555,14 @@ func runCnbBuild(config *cnbBuildOptions, telemetryData *telemetry.CustomData, t | ||||
| 		return errors.Wrapf(err, "execution of '%s' failed", creatorArgs) | ||||
| 	} | ||||
|  | ||||
| 	digest, err := cnbutils.DigestFromReport(utils) | ||||
| 	if err != nil { | ||||
| 		log.SetErrorCategory(log.ErrorBuild) | ||||
| 		return errors.Wrap(err, "failed to read image digest") | ||||
| 	} | ||||
| 	commonPipelineEnvironment.container.imageDigest = digest | ||||
| 	commonPipelineEnvironment.container.imageDigests = append(commonPipelineEnvironment.container.imageDigests, digest) | ||||
|  | ||||
| 	if len(config.PreserveFiles) > 0 { | ||||
| 		if pathType != pathEnumArchive { | ||||
| 			err = cnbutils.CopyProject(target, source, ignore.CompileIgnoreLines(config.PreserveFiles...), nil, utils) | ||||
|   | ||||
| @@ -36,9 +36,11 @@ type cnbBuildOptions struct { | ||||
| type cnbBuildCommonPipelineEnvironment struct { | ||||
| 	container struct { | ||||
| 		registryURL   string | ||||
| 		imageDigest   string | ||||
| 		imageNameTag  string | ||||
| 		imageNames    []string | ||||
| 		imageNameTags []string | ||||
| 		imageDigests  []string | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -49,9 +51,11 @@ func (p *cnbBuildCommonPipelineEnvironment) persist(path, resourceName string) { | ||||
| 		value    interface{} | ||||
| 	}{ | ||||
| 		{category: "container", name: "registryUrl", value: p.container.registryURL}, | ||||
| 		{category: "container", name: "imageDigest", value: p.container.imageDigest}, | ||||
| 		{category: "container", name: "imageNameTag", value: p.container.imageNameTag}, | ||||
| 		{category: "container", name: "imageNames", value: p.container.imageNames}, | ||||
| 		{category: "container", name: "imageNameTags", value: p.container.imageNameTags}, | ||||
| 		{category: "container", name: "imageDigests", value: p.container.imageDigests}, | ||||
| 	} | ||||
|  | ||||
| 	errCount := 0 | ||||
| @@ -348,9 +352,11 @@ func cnbBuildMetadata() config.StepData { | ||||
| 						Type: "piperEnvironment", | ||||
| 						Parameters: []map[string]interface{}{ | ||||
| 							{"name": "container/registryUrl"}, | ||||
| 							{"name": "container/imageDigest"}, | ||||
| 							{"name": "container/imageNameTag"}, | ||||
| 							{"name": "container/imageNames", "type": "[]string"}, | ||||
| 							{"name": "container/imageNameTags", "type": "[]string"}, | ||||
| 							{"name": "container/imageDigests", "type": "[]string"}, | ||||
| 						}, | ||||
| 					}, | ||||
| 				}, | ||||
|   | ||||
| @@ -23,6 +23,11 @@ func newCnbBuildTestsUtils() cnbutils.MockUtils { | ||||
| 		ExecMockRunner: &mock.ExecMockRunner{}, | ||||
| 		FilesMock:      &mock.FilesMock{}, | ||||
| 	} | ||||
| 	utils.AddFile("/layers/report.toml", []byte(`[build] | ||||
| [image] | ||||
| tags = ["localhost:5000/not-found:0.0.1"] | ||||
| digest = "sha256:52eac630560210e5ae13eb10797c4246d6f02d425f32b9430ca00bde697c79ec" | ||||
| manifest-size = 2388`)) | ||||
| 	return utils | ||||
| } | ||||
|  | ||||
| @@ -101,6 +106,9 @@ func TestRunCnbBuild(t *testing.T) { | ||||
| 		assert.Equal(t, config.ContainerRegistryURL, commonPipelineEnvironment.container.registryURL) | ||||
| 		assert.Equal(t, "io-buildpacks-my-app:0.0.1", commonPipelineEnvironment.container.imageNameTag) | ||||
|  | ||||
| 		assert.Equal(t, "sha256:52eac630560210e5ae13eb10797c4246d6f02d425f32b9430ca00bde697c79ec", commonPipelineEnvironment.container.imageDigest) | ||||
| 		assert.Contains(t, commonPipelineEnvironment.container.imageDigests, "sha256:52eac630560210e5ae13eb10797c4246d6f02d425f32b9430ca00bde697c79ec") | ||||
|  | ||||
| 		customDataAsString := telemetryData.Custom1 | ||||
| 		customData := cnbBuildTelemetry{} | ||||
| 		err = json.Unmarshal([]byte(customDataAsString), &customData) | ||||
| @@ -539,6 +547,7 @@ uri = "some-buildpack" | ||||
| 		customDataAsString := telemetryData.Custom1 | ||||
| 		customData := cnbBuildTelemetry{} | ||||
| 		err = json.Unmarshal([]byte(customDataAsString), &customData) | ||||
| 		assert.NoError(t, err) | ||||
| 		require.Equal(t, expectedImageCount, len(customData.Data)) | ||||
|  | ||||
| 		runner := utils.ExecMockRunner | ||||
|   | ||||
| @@ -44,8 +44,8 @@ func TestNpmProject(t *testing.T) { | ||||
| 		Network: fmt.Sprintf("container:%s", registryContainer.GetContainerID()), | ||||
| 	}) | ||||
|  | ||||
| 	container.whenRunningPiperCommand("cnbBuild", "--customConfig", "TestCnbIntegration/config_env.yml", "--path", "TestMtaIntegration/npm", "--containerImageName", "not-found", "--containerImageTag", "0.0.1", "--containerRegistryUrl", registryURL) | ||||
|  | ||||
| 	err := container.whenRunningPiperCommand("cnbBuild", "--customConfig", "TestCnbIntegration/config_env.yml", "--path", "TestMtaIntegration/npm", "--containerImageName", "not-found", "--containerImageTag", "0.0.1", "--containerRegistryUrl", registryURL) | ||||
| 	assert.NoError(t, err) | ||||
| 	container.assertHasOutput(t, "running command: /cnb/lifecycle/creator") | ||||
| 	container.assertHasOutput(t, "Selected Node Engine version (using BP_NODE_VERSION): 16") | ||||
| 	container.assertHasOutput(t, "Paketo NPM Start Buildpack") | ||||
|   | ||||
| @@ -1,3 +1,5 @@ | ||||
| general: | ||||
|   verbose: true | ||||
| steps: | ||||
|   cnbBuild: | ||||
|     buildEnvVars: | ||||
|   | ||||
							
								
								
									
										33
									
								
								pkg/cnbutils/report.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								pkg/cnbutils/report.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| package cnbutils | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
|  | ||||
| 	"github.com/SAP/jenkins-library/pkg/log" | ||||
| 	"github.com/buildpacks/lifecycle/platform" | ||||
| 	"github.com/pelletier/go-toml" | ||||
| ) | ||||
|  | ||||
| const reportFile = "/layers/report.toml" | ||||
|  | ||||
| func DigestFromReport(utils BuildUtils) (string, error) { | ||||
| 	report := platform.ExportReport{} | ||||
|  | ||||
| 	data, err := utils.FileRead(reportFile) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	err = toml.Unmarshal(data, &report) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	log.Entry().Debugf("Image report: %#v\n", report) | ||||
|  | ||||
| 	if report.Image.Digest == "" { | ||||
| 		return "", fmt.Errorf("image digest is empty") | ||||
| 	} | ||||
|  | ||||
| 	return report.Image.Digest, nil | ||||
| } | ||||
							
								
								
									
										48
									
								
								pkg/cnbutils/report_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								pkg/cnbutils/report_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,48 @@ | ||||
| package cnbutils_test | ||||
|  | ||||
| import ( | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/SAP/jenkins-library/pkg/cnbutils" | ||||
| 	"github.com/SAP/jenkins-library/pkg/mock" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| func TestDigestFromReport(t *testing.T) { | ||||
| 	t.Run("return a digest from the report.toml", func(t *testing.T) { | ||||
| 		mockUtils := &cnbutils.MockUtils{ | ||||
| 			FilesMock: &mock.FilesMock{}, | ||||
| 		} | ||||
| 		mockUtils.AddFile("/layers/report.toml", []byte(`[build] | ||||
| [image] | ||||
| digest = "sha256:52eac630560210e5ae13eb10797c4246d6f02d425f32b9430ca00bde697c79ec" | ||||
| `)) | ||||
| 		digest, err := cnbutils.DigestFromReport(mockUtils) | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, "sha256:52eac630560210e5ae13eb10797c4246d6f02d425f32b9430ca00bde697c79ec", digest) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("fails if digest is empty", func(t *testing.T) { | ||||
| 		mockUtils := &cnbutils.MockUtils{ | ||||
| 			ExecMockRunner: &mock.ExecMockRunner{}, | ||||
| 			FilesMock:      &mock.FilesMock{}, | ||||
| 		} | ||||
| 		mockUtils.AddFile("/layers/report.toml", []byte(``)) | ||||
|  | ||||
| 		digest, err := cnbutils.DigestFromReport(mockUtils) | ||||
| 		assert.Empty(t, digest) | ||||
| 		assert.EqualError(t, err, "image digest is empty") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("fails to unmarshal corrupted file", func(t *testing.T) { | ||||
| 		mockUtils := &cnbutils.MockUtils{ | ||||
| 			ExecMockRunner: &mock.ExecMockRunner{}, | ||||
| 			FilesMock:      &mock.FilesMock{}, | ||||
| 		} | ||||
| 		mockUtils.AddFile("/layers/report.toml", []byte(`{}`)) | ||||
|  | ||||
| 		digest, err := cnbutils.DigestFromReport(mockUtils) | ||||
| 		assert.Empty(t, digest) | ||||
| 		assert.EqualError(t, err, "(1, 1): parsing error: keys cannot contain { character") | ||||
| 	}) | ||||
| } | ||||
| @@ -236,10 +236,13 @@ spec: | ||||
|         type: piperEnvironment | ||||
|         params: | ||||
|           - name: container/registryUrl | ||||
|           - name: container/imageDigest | ||||
|           - name: container/imageNameTag | ||||
|           - name: container/imageNames | ||||
|             type: "[]string" | ||||
|           - name: container/imageNameTags | ||||
|             type: "[]string" | ||||
|           - name: container/imageDigests | ||||
|             type: "[]string" | ||||
|   containers: | ||||
|     - image: "paketobuildpacks/builder:full" | ||||
|   | ||||
		Reference in New Issue
	
	Block a user