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(gradleExecuteBuild, fortifyExecuteScan): gradle improvements (#3807)
* Improvements were made * fixed tests * fixed issues * fix versioning * fix Inclusive Language warnings * gradle support to fortifyExecuteScan. Classpath resolving Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>
This commit is contained in:
		
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							aecf1babd9
						
					
				
				
					commit
					92837fde18
				
			| @@ -62,6 +62,7 @@ type artifactPrepareVersionUtils interface { | ||||
| 	MkdirAll(path string, perm os.FileMode) error | ||||
| 	FileWrite(path string, content []byte, perm os.FileMode) error | ||||
| 	FileRead(path string) ([]byte, error) | ||||
| 	FileRemove(path string) error | ||||
|  | ||||
| 	NewOrchestratorSpecificConfigProvider() (orchestrator.OrchestratorSpecificConfigProviding, error) | ||||
| } | ||||
|   | ||||
| @@ -39,6 +39,16 @@ import ( | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
|  | ||||
| const getClasspathScriptContent = ` | ||||
| gradle.allprojects { | ||||
|     task getClasspath { | ||||
|         doLast { | ||||
|             new File(projectDir, filename).text = sourceSets.main.compileClasspath.asPath | ||||
|         } | ||||
|     } | ||||
| } | ||||
| ` | ||||
|  | ||||
| type pullRequestService interface { | ||||
| 	ListPullRequestsWithCommit(ctx context.Context, owner, repo, sha string, opts *github.PullRequestListOptions) ([]*github.PullRequest, *github.Response, error) | ||||
| } | ||||
| @@ -712,6 +722,19 @@ func autoresolveMavenClasspath(config fortifyExecuteScanOptions, file string, ut | ||||
| 	return readAllClasspathFiles(file), nil | ||||
| } | ||||
|  | ||||
| func autoresolveGradleClasspath(config fortifyExecuteScanOptions, file string, utils fortifyUtils) (string, error) { | ||||
| 	gradleOptions := &gradle.ExecuteOptions{ | ||||
| 		Task:              "getClasspath", | ||||
| 		UseWrapper:        true, | ||||
| 		InitScriptContent: getClasspathScriptContent, | ||||
| 		ProjectProperties: map[string]string{"filename": file}, | ||||
| 	} | ||||
| 	if _, err := gradle.Execute(gradleOptions, utils); err != nil { | ||||
| 		log.Entry().WithError(err).Warnf("failed to determine classpath using Gradle: %v", err) | ||||
| 	} | ||||
| 	return readAllClasspathFiles(file), nil | ||||
| } | ||||
|  | ||||
| func generateMavenFortifyDefines(config *fortifyExecuteScanOptions, file string) []string { | ||||
| 	defines := []string{ | ||||
| 		fmt.Sprintf("-Dmdep.outputFile=%v", file), | ||||
| @@ -814,7 +837,18 @@ func triggerFortifyScan(config fortifyExecuteScanOptions, utils fortifyUtils, bu | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 		config.Translate, err = populateMavenTranslate(&config, classpath) | ||||
| 		config.Translate, err = populateMavenGradleTranslate(&config, classpath) | ||||
| 		if err != nil { | ||||
| 			log.Entry().WithError(err).Warnf("failed to apply src ('%s') or exclude ('%s') parameter", config.Src, config.Exclude) | ||||
| 		} | ||||
| 	} else if config.BuildTool == "gradle" { | ||||
| 		if config.AutodetectClasspath { | ||||
| 			classpath, err = autoresolveGradleClasspath(config, classpathFileName, utils) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 		config.Translate, err = populateMavenGradleTranslate(&config, classpath) | ||||
| 		if err != nil { | ||||
| 			log.Entry().WithError(err).Warnf("failed to apply src ('%s') or exclude ('%s') parameter", config.Src, config.Exclude) | ||||
| 		} | ||||
| @@ -876,7 +910,7 @@ func populatePipTranslate(config *fortifyExecuteScanOptions, classpath string) ( | ||||
| 	return string(translateJSON), err | ||||
| } | ||||
|  | ||||
| func populateMavenTranslate(config *fortifyExecuteScanOptions, classpath string) (string, error) { | ||||
| func populateMavenGradleTranslate(config *fortifyExecuteScanOptions, classpath string) (string, error) { | ||||
| 	if len(config.Translate) > 0 { | ||||
| 		return config.Translate, nil | ||||
| 	} | ||||
| @@ -1019,7 +1053,7 @@ func appendToOptions(config *fortifyExecuteScanOptions, options []string, t map[ | ||||
| 			options = append(options, "-libdirs", t["libDirs"]) | ||||
| 		} | ||||
|  | ||||
| 	case "maven": | ||||
| 	case "maven", "gradle": | ||||
| 		if len(t["autoClasspath"]) > 0 { | ||||
| 			options = append(options, "-cp", t["autoClasspath"]) | ||||
| 		} else if len(t["classpath"]) > 0 { | ||||
|   | ||||
| @@ -923,21 +923,21 @@ func TestAutoresolveClasspath(t *testing.T) { | ||||
| func TestPopulateMavenTranslate(t *testing.T) { | ||||
| 	t.Run("src without translate", func(t *testing.T) { | ||||
| 		config := fortifyExecuteScanOptions{Src: []string{"./**/*"}} | ||||
| 		translate, err := populateMavenTranslate(&config, "") | ||||
| 		translate, err := populateMavenGradleTranslate(&config, "") | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, `[{"classpath":"","exclude":"**/src/test/**/*","src":"./**/*"}]`, translate) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("exclude without translate", func(t *testing.T) { | ||||
| 		config := fortifyExecuteScanOptions{Exclude: []string{"./**/*"}} | ||||
| 		translate, err := populateMavenTranslate(&config, "") | ||||
| 		translate, err := populateMavenGradleTranslate(&config, "") | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, `[{"classpath":"","exclude":"./**/*","src":"**/*.xml:**/*.html:**/*.jsp:**/*.js:**/src/main/resources/**/*:**/src/main/java/**/*:**/target/main/java/**/*:**/target/main/resources/**/*:**/target/generated-sources/**/*"}]`, translate) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("with translate", func(t *testing.T) { | ||||
| 		config := fortifyExecuteScanOptions{Translate: `[{"classpath":""}]`, Src: []string{"./**/*"}, Exclude: []string{"./**/*"}} | ||||
| 		translate, err := populateMavenTranslate(&config, "ignored/path") | ||||
| 		translate, err := populateMavenGradleTranslate(&config, "ignored/path") | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, `[{"classpath":""}]`, translate) | ||||
| 	}) | ||||
|   | ||||
| @@ -1,8 +1,9 @@ | ||||
| package cmd | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"text/template" | ||||
|  | ||||
| 	"github.com/SAP/jenkins-library/pkg/command" | ||||
| 	"github.com/SAP/jenkins-library/pkg/gradle" | ||||
| @@ -11,10 +12,75 @@ import ( | ||||
| 	"github.com/SAP/jenkins-library/pkg/telemetry" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	bomGradleTaskName = "cyclonedxBom" | ||||
| 	publishTaskName   = "publish" | ||||
| ) | ||||
|  | ||||
| const publishInitScriptContentTemplate = ` | ||||
| rootProject { | ||||
|     apply plugin: 'maven-publish' | ||||
|     apply plugin: 'java' | ||||
|  | ||||
|     publishing { | ||||
|         publications { | ||||
|             maven(MavenPublication) { | ||||
|                 versionMapping { | ||||
|                     usage('java-api') { | ||||
|                         fromResolutionOf('runtimeClasspath') | ||||
|                     } | ||||
|                     usage('java-runtime') { | ||||
|                         fromResolutionResult() | ||||
|                     } | ||||
|                 } | ||||
| 				{{- if .ArtifactGroupID}} | ||||
| 				groupId = '{{.ArtifactGroupID}}' | ||||
| 				{{- end }} | ||||
| 				{{- if .ArtifactID}} | ||||
| 				artifactId = '{{.ArtifactID}}' | ||||
| 				{{- end }} | ||||
| 				{{- if .ArtifactVersion}} | ||||
| 				version = '{{.ArtifactVersion}}' | ||||
| 				{{- end }} | ||||
|                 from components.java | ||||
|             } | ||||
|         } | ||||
|         repositories { | ||||
|             maven { | ||||
|                 credentials { | ||||
|                     username = "{{.RepositoryUsername}}" | ||||
|                     password = "{{.RepositoryPassword}}" | ||||
|                 } | ||||
|                 url = "{{.RepositoryURL}}" | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| ` | ||||
|  | ||||
| const bomInitScriptContent = ` | ||||
| initscript { | ||||
|   repositories { | ||||
|     mavenCentral() | ||||
|     maven { | ||||
|       url "https://plugins.gradle.org/m2/" | ||||
|     } | ||||
|   } | ||||
|   dependencies { | ||||
|     classpath "com.cyclonedx:cyclonedx-gradle-plugin:1.5.0" | ||||
|   } | ||||
| } | ||||
|  | ||||
| rootProject { | ||||
|     apply plugin: 'java' | ||||
|     apply plugin: 'maven' | ||||
|     apply plugin: org.cyclonedx.gradle.CycloneDxPlugin | ||||
| } | ||||
| ` | ||||
|  | ||||
| type gradleExecuteBuildUtils interface { | ||||
| 	command.ExecRunner | ||||
| 	piperutils.FileUtils | ||||
| 	DownloadFile(url, filename string, header http.Header, cookies []*http.Cookie) error | ||||
| } | ||||
|  | ||||
| type gradleExecuteBuildUtilsBundle struct { | ||||
| @@ -22,10 +88,6 @@ type gradleExecuteBuildUtilsBundle struct { | ||||
| 	*piperutils.Files | ||||
| } | ||||
|  | ||||
| func (g *gradleExecuteBuildUtilsBundle) DownloadFile(url, filename string, header http.Header, cookies []*http.Cookie) error { | ||||
| 	return fmt.Errorf("not implemented") | ||||
| } | ||||
|  | ||||
| func newGradleExecuteBuildUtils() gradleExecuteBuildUtils { | ||||
| 	utils := gradleExecuteBuildUtilsBundle{ | ||||
| 		Command: &command.Command{}, | ||||
| @@ -45,23 +107,77 @@ func gradleExecuteBuild(config gradleExecuteBuildOptions, telemetryData *telemet | ||||
| } | ||||
|  | ||||
| func runGradleExecuteBuild(config *gradleExecuteBuildOptions, telemetryData *telemetry.CustomData, utils gradleExecuteBuildUtils) error { | ||||
| 	opt := &gradle.ExecuteOptions{ | ||||
| 		BuildGradlePath:    config.Path, | ||||
| 		Task:               config.Task, | ||||
| 		CreateBOM:          config.CreateBOM, | ||||
| 		Publish:            config.Publish, | ||||
| 		RepositoryURL:      config.RepositoryURL, | ||||
| 		RepositoryPassword: config.RepositoryPassword, | ||||
| 		RepositoryUsername: config.RepositoryUsername, | ||||
| 		ArtifactVersion:    config.ArtifactVersion, | ||||
| 		ArtifactGroupID:    config.ArtifactGroupID, | ||||
| 		ArtifactID:         config.ArtifactID, | ||||
| 	log.Entry().Info("BOM file creation...") | ||||
| 	if config.CreateBOM { | ||||
| 		if err := createBOM(config, utils); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if err := gradle.Execute(opt, utils); err != nil { | ||||
| 	// gradle build | ||||
| 	gradleOptions := &gradle.ExecuteOptions{ | ||||
| 		BuildGradlePath: config.Path, | ||||
| 		Task:            config.Task, | ||||
| 		UseWrapper:      config.UseWrapper, | ||||
| 	} | ||||
| 	if _, err := gradle.Execute(gradleOptions, utils); err != nil { | ||||
| 		log.Entry().WithError(err).Errorf("gradle build execution was failed: %v", err) | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	log.Entry().Info("Publishing of artifacts to staging repository...") | ||||
| 	if config.Publish { | ||||
| 		if err := publishArtifacts(config, utils); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func createBOM(config *gradleExecuteBuildOptions, utils gradleExecuteBuildUtils) error { | ||||
| 	gradleOptions := &gradle.ExecuteOptions{ | ||||
| 		BuildGradlePath:   config.Path, | ||||
| 		Task:              bomGradleTaskName, | ||||
| 		UseWrapper:        config.UseWrapper, | ||||
| 		InitScriptContent: bomInitScriptContent, | ||||
| 	} | ||||
| 	if _, err := gradle.Execute(gradleOptions, utils); err != nil { | ||||
| 		log.Entry().WithError(err).Errorf("failed to create BOM: %v", err) | ||||
| 		return err | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func publishArtifacts(config *gradleExecuteBuildOptions, utils gradleExecuteBuildUtils) error { | ||||
| 	publishInitScriptContent, err := getPublishInitScriptContent(config) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("failed to get publish init script content: %v", err) | ||||
| 	} | ||||
| 	gradleOptions := &gradle.ExecuteOptions{ | ||||
| 		BuildGradlePath:   config.Path, | ||||
| 		Task:              publishTaskName, | ||||
| 		UseWrapper:        config.UseWrapper, | ||||
| 		InitScriptContent: publishInitScriptContent, | ||||
| 	} | ||||
| 	if _, err := gradle.Execute(gradleOptions, utils); err != nil { | ||||
| 		log.Entry().WithError(err).Errorf("failed to publish artifacts: %v", err) | ||||
| 		return err | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func getPublishInitScriptContent(options *gradleExecuteBuildOptions) (string, error) { | ||||
| 	tmpl, err := template.New("resources").Parse(publishInitScriptContentTemplate) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	var generatedCode bytes.Buffer | ||||
| 	err = tmpl.Execute(&generatedCode, options) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	return string(generatedCode.Bytes()), nil | ||||
| } | ||||
|   | ||||
| @@ -30,6 +30,7 @@ type gradleExecuteBuildOptions struct { | ||||
| 	ArtifactVersion    string `json:"artifactVersion,omitempty"` | ||||
| 	ArtifactGroupID    string `json:"artifactGroupId,omitempty"` | ||||
| 	ArtifactID         string `json:"artifactId,omitempty"` | ||||
| 	UseWrapper         bool   `json:"useWrapper,omitempty"` | ||||
| } | ||||
|  | ||||
| type gradleExecuteBuildReports struct { | ||||
| @@ -171,6 +172,7 @@ func addGradleExecuteBuildFlags(cmd *cobra.Command, stepConfig *gradleExecuteBui | ||||
| 	cmd.Flags().StringVar(&stepConfig.ArtifactVersion, "artifactVersion", os.Getenv("PIPER_artifactVersion"), "Version of the artifact to be built.") | ||||
| 	cmd.Flags().StringVar(&stepConfig.ArtifactGroupID, "artifactGroupId", os.Getenv("PIPER_artifactGroupId"), "The group of the artifact.") | ||||
| 	cmd.Flags().StringVar(&stepConfig.ArtifactID, "artifactId", os.Getenv("PIPER_artifactId"), "The name of the artifact.") | ||||
| 	cmd.Flags().BoolVar(&stepConfig.UseWrapper, "useWrapper", false, "If set to false all commands are executed using 'gradle', otherwise 'gradlew' is executed.") | ||||
|  | ||||
| } | ||||
|  | ||||
| @@ -305,6 +307,15 @@ func gradleExecuteBuildMetadata() config.StepData { | ||||
| 						Aliases:   []config.Alias{}, | ||||
| 						Default:   os.Getenv("PIPER_artifactId"), | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "useWrapper", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"STEPS", "STAGES", "PARAMETERS"}, | ||||
| 						Type:        "bool", | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 						Default:     false, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			Containers: []config.Container{ | ||||
|   | ||||
| @@ -1,11 +1,9 @@ | ||||
| package cmd | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"strings" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/pkg/errors" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
|  | ||||
| 	"github.com/SAP/jenkins-library/pkg/mock" | ||||
| @@ -16,47 +14,165 @@ type gradleExecuteBuildMockUtils struct { | ||||
| 	*mock.FilesMock | ||||
| } | ||||
|  | ||||
| func (f gradleExecuteBuildMockUtils) DirExists(path string) (bool, error) { | ||||
| 	return strings.EqualFold(path, "path/to/"), nil | ||||
| } | ||||
|  | ||||
| func (f gradleExecuteBuildMockUtils) FileExists(filePath string) (bool, error) { | ||||
| 	return strings.EqualFold(filePath, "path/to/build.gradle"), nil | ||||
| } | ||||
|  | ||||
| func (f gradleExecuteBuildMockUtils) DownloadFile(url, filename string, header http.Header, cookies []*http.Cookie) error { | ||||
| 	return fmt.Errorf("not implemented") | ||||
| } | ||||
|  | ||||
| func newGradleExecuteBuildTestsUtils() gradleExecuteBuildMockUtils { | ||||
| 	utils := gradleExecuteBuildMockUtils{ | ||||
| 		ExecMockRunner: &mock.ExecMockRunner{}, | ||||
| 		FilesMock:      &mock.FilesMock{}, | ||||
| 	} | ||||
| 	return utils | ||||
| } | ||||
|  | ||||
| func TestRunGradleExecuteBuild(t *testing.T) { | ||||
|  | ||||
| 	t.Run("negative case - build.gradle isn't present", func(t *testing.T) { | ||||
| 	t.Run("failed case - build.gradle isn't present", func(t *testing.T) { | ||||
| 		utils := gradleExecuteBuildMockUtils{ | ||||
| 			ExecMockRunner: &mock.ExecMockRunner{}, | ||||
| 			FilesMock:      &mock.FilesMock{}, | ||||
| 		} | ||||
| 		options := &gradleExecuteBuildOptions{ | ||||
| 			Path: "path/to/project/", | ||||
| 			Path:       "path/to", | ||||
| 			Task:       "build", | ||||
| 			UseWrapper: false, | ||||
| 		} | ||||
| 		u := newGradleExecuteBuildTestsUtils() | ||||
|  | ||||
| 		err := runGradleExecuteBuild(options, nil, u) | ||||
| 		assert.EqualError(t, err, "the specified gradle build script could not be found") | ||||
| 		err := runGradleExecuteBuild(options, nil, utils) | ||||
| 		assert.Error(t, err) | ||||
| 		assert.Contains(t, err.Error(), "the specified gradle build script could not be found") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("success case - build.gradle is present", func(t *testing.T) { | ||||
| 		o := &gradleExecuteBuildOptions{ | ||||
| 			Path: "path/to/", | ||||
| 	t.Run("success case - only build", func(t *testing.T) { | ||||
| 		utils := gradleExecuteBuildMockUtils{ | ||||
| 			ExecMockRunner: &mock.ExecMockRunner{}, | ||||
| 			FilesMock:      &mock.FilesMock{}, | ||||
| 		} | ||||
| 		utils.FilesMock.AddFile("path/to/build.gradle", []byte{}) | ||||
| 		options := &gradleExecuteBuildOptions{ | ||||
| 			Path:       "path/to", | ||||
| 			Task:       "build", | ||||
| 			UseWrapper: false, | ||||
| 		} | ||||
|  | ||||
| 		u := newGradleExecuteBuildTestsUtils() | ||||
|  | ||||
| 		err := runGradleExecuteBuild(o, nil, u) | ||||
| 		err := runGradleExecuteBuild(options, nil, utils) | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, 1, len(utils.Calls)) | ||||
| 		assert.Equal(t, mock.ExecCall{Exec: "gradle", Params: []string{"build", "-p", "path/to"}}, utils.Calls[0]) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("success case - bom creation", func(t *testing.T) { | ||||
| 		utils := gradleExecuteBuildMockUtils{ | ||||
| 			ExecMockRunner: &mock.ExecMockRunner{}, | ||||
| 			FilesMock:      &mock.FilesMock{}, | ||||
| 		} | ||||
| 		utils.FilesMock.AddFile("path/to/build.gradle", []byte{}) | ||||
| 		options := &gradleExecuteBuildOptions{ | ||||
| 			Path:       "path/to", | ||||
| 			Task:       "build", | ||||
| 			UseWrapper: false, | ||||
| 			CreateBOM:  true, | ||||
| 		} | ||||
|  | ||||
| 		err := runGradleExecuteBuild(options, nil, utils) | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, 3, len(utils.Calls)) | ||||
| 		assert.Equal(t, mock.ExecCall{Exec: "gradle", Params: []string{"tasks", "-p", "path/to"}}, utils.Calls[0]) | ||||
| 		assert.Equal(t, mock.ExecCall{Execution: (*mock.Execution)(nil), Async: false, Exec: "gradle", Params: []string{"cyclonedxBom", "-p", "path/to", "--init-script", "initScript.gradle.tmp"}}, utils.Calls[1]) | ||||
| 		assert.Equal(t, mock.ExecCall{Exec: "gradle", Params: []string{"build", "-p", "path/to"}}, utils.Calls[2]) | ||||
| 		assert.True(t, utils.HasWrittenFile("initScript.gradle.tmp")) | ||||
| 		assert.True(t, utils.HasRemovedFile("initScript.gradle.tmp")) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("success case - publishing of artifacts", func(t *testing.T) { | ||||
| 		utils := gradleExecuteBuildMockUtils{ | ||||
| 			ExecMockRunner: &mock.ExecMockRunner{}, | ||||
| 			FilesMock:      &mock.FilesMock{}, | ||||
| 		} | ||||
| 		utils.FilesMock.AddFile("path/to/build.gradle", []byte{}) | ||||
| 		options := &gradleExecuteBuildOptions{ | ||||
| 			Path:       "path/to", | ||||
| 			Task:       "build", | ||||
| 			UseWrapper: false, | ||||
| 			Publish:    true, | ||||
| 		} | ||||
|  | ||||
| 		err := runGradleExecuteBuild(options, nil, utils) | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, 3, len(utils.Calls)) | ||||
| 		assert.Equal(t, mock.ExecCall{Exec: "gradle", Params: []string{"build", "-p", "path/to"}}, utils.Calls[0]) | ||||
| 		assert.Equal(t, mock.ExecCall{Exec: "gradle", Params: []string{"tasks", "-p", "path/to"}}, utils.Calls[1]) | ||||
| 		assert.Equal(t, mock.ExecCall{Execution: (*mock.Execution)(nil), Async: false, Exec: "gradle", Params: []string{"publish", "-p", "path/to", "--init-script", "initScript.gradle.tmp"}}, utils.Calls[2]) | ||||
| 		assert.True(t, utils.HasWrittenFile("initScript.gradle.tmp")) | ||||
| 		assert.True(t, utils.HasRemovedFile("initScript.gradle.tmp")) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("success case - build using wrapper", func(t *testing.T) { | ||||
| 		utils := gradleExecuteBuildMockUtils{ | ||||
| 			ExecMockRunner: &mock.ExecMockRunner{}, | ||||
| 			FilesMock:      &mock.FilesMock{}, | ||||
| 		} | ||||
| 		utils.FilesMock.AddFile("path/to/build.gradle", []byte{}) | ||||
| 		utils.FilesMock.AddFile("gradlew", []byte{}) | ||||
| 		options := &gradleExecuteBuildOptions{ | ||||
| 			Path:       "path/to", | ||||
| 			Task:       "build", | ||||
| 			UseWrapper: true, | ||||
| 		} | ||||
|  | ||||
| 		err := runGradleExecuteBuild(options, nil, utils) | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, 1, len(utils.Calls)) | ||||
| 		assert.Equal(t, mock.ExecCall{Exec: "./gradlew", Params: []string{"build", "-p", "path/to"}}, utils.Calls[0]) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("failed case - build", func(t *testing.T) { | ||||
| 		utils := gradleExecuteBuildMockUtils{ | ||||
| 			ExecMockRunner: &mock.ExecMockRunner{ | ||||
| 				ShouldFailOnCommand: map[string]error{"gradle build -p path/to": errors.New("failed to build")}, | ||||
| 			}, | ||||
| 			FilesMock: &mock.FilesMock{}, | ||||
| 		} | ||||
| 		utils.FilesMock.AddFile("path/to/build.gradle", []byte{}) | ||||
| 		options := &gradleExecuteBuildOptions{ | ||||
| 			Path:       "path/to", | ||||
| 			Task:       "build", | ||||
| 			UseWrapper: false, | ||||
| 		} | ||||
|  | ||||
| 		err := runGradleExecuteBuild(options, nil, utils) | ||||
| 		assert.Error(t, err) | ||||
| 		assert.Contains(t, err.Error(), "failed to build") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("failed case - bom creation", func(t *testing.T) { | ||||
| 		utils := gradleExecuteBuildMockUtils{ | ||||
| 			ExecMockRunner: &mock.ExecMockRunner{ | ||||
| 				ShouldFailOnCommand: map[string]error{"./gradlew cyclonedxBom -p path/to --init-script initScript.gradle.tmp": errors.New("failed to create bom")}, | ||||
| 			}, | ||||
| 			FilesMock: &mock.FilesMock{}, | ||||
| 		} | ||||
| 		utils.FilesMock.AddFile("path/to/build.gradle", []byte{}) | ||||
| 		utils.FilesMock.AddFile("gradlew", []byte{}) | ||||
| 		options := &gradleExecuteBuildOptions{ | ||||
| 			Path:       "path/to", | ||||
| 			Task:       "build", | ||||
| 			UseWrapper: true, | ||||
| 			CreateBOM:  true, | ||||
| 		} | ||||
|  | ||||
| 		err := runGradleExecuteBuild(options, nil, utils) | ||||
| 		assert.Error(t, err) | ||||
| 		assert.Contains(t, err.Error(), "failed to create bom") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("failed case - publish artifacts", func(t *testing.T) { | ||||
| 		utils := gradleExecuteBuildMockUtils{ | ||||
| 			ExecMockRunner: &mock.ExecMockRunner{ | ||||
| 				ShouldFailOnCommand: map[string]error{"./gradlew publish -p path/to --init-script initScript.gradle.tmp": errors.New("failed to publish artifacts")}, | ||||
| 			}, | ||||
| 			FilesMock: &mock.FilesMock{}, | ||||
| 		} | ||||
| 		utils.FilesMock.AddFile("path/to/build.gradle", []byte{}) | ||||
| 		utils.FilesMock.AddFile("gradlew", []byte{}) | ||||
| 		options := &gradleExecuteBuildOptions{ | ||||
| 			Path:       "path/to", | ||||
| 			Task:       "build", | ||||
| 			UseWrapper: true, | ||||
| 			Publish:    true, | ||||
| 		} | ||||
|  | ||||
| 		err := runGradleExecuteBuild(options, nil, utils) | ||||
| 		assert.Error(t, err) | ||||
| 		assert.Contains(t, err.Error(), "failed to publish artifacts") | ||||
| 	}) | ||||
| } | ||||
|   | ||||
| @@ -17,7 +17,7 @@ import ( | ||||
| 	"github.com/testcontainers/testcontainers-go" | ||||
| ) | ||||
|  | ||||
| func TestGradleExecuteBuild_JavaProject_BOMCreation(t *testing.T) { | ||||
| func TestGradleExecuteBuild_JavaProject_BOMCreation_UsingWrapper(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 	ctx := context.Background() | ||||
|  | ||||
| @@ -38,12 +38,12 @@ func TestGradleExecuteBuild_JavaProject_BOMCreation(t *testing.T) { | ||||
| 	//workaround to use test script util it is possible to set workdir for Exec call | ||||
| 	testScript := fmt.Sprintf(`#!/bin/sh | ||||
| cd /test | ||||
| /piperbin/piper gradleExecuteBuild --createBOM >test-log.txt 2>&1 | ||||
| /piperbin/piper gradleExecuteBuild >test-log.txt 2>&1 | ||||
| `) | ||||
| 	ioutil.WriteFile(filepath.Join(tempDir, "runPiper.sh"), []byte(testScript), 0700) | ||||
|  | ||||
| 	reqNode := testcontainers.ContainerRequest{ | ||||
| 		Image: "gradle:6-jdk11-alpine", | ||||
| 		Image: "adoptopenjdk/openjdk11:jdk-11.0.11_9-alpine", | ||||
| 		Cmd:   []string{"tail", "-f"}, | ||||
| 		BindMounts: map[string]string{ | ||||
| 			pwd:     "/piperbin", | ||||
| @@ -65,9 +65,9 @@ cd /test | ||||
| 		t.Fatal("Could not read test-log.txt.", err) | ||||
| 	} | ||||
| 	output := string(content) | ||||
| 	assert.Contains(t, output, "info  gradleExecuteBuild - running command: gradle tasks") | ||||
| 	assert.Contains(t, output, "info  gradleExecuteBuild - running command: gradle --init-script cyclonedx.gradle cyclonedxBom") | ||||
| 	assert.Contains(t, output, "info  gradleExecuteBuild - running command: gradle build") | ||||
| 	assert.Contains(t, output, "info  gradleExecuteBuild - running command: ./gradlew tasks") | ||||
| 	assert.Contains(t, output, "info  gradleExecuteBuild - running command: ./gradlew cyclonedxBom --init-script initScript.gradle.tmp") | ||||
| 	assert.Contains(t, output, "info  gradleExecuteBuild - running command: ./gradlew build") | ||||
| 	assert.Contains(t, output, "info  gradleExecuteBuild - BUILD SUCCESSFUL") | ||||
| 	assert.Contains(t, output, "info  gradleExecuteBuild - SUCCESS") | ||||
|  | ||||
| @@ -139,7 +139,7 @@ cd /test | ||||
| 	} | ||||
| 	output := string(content) | ||||
| 	assert.Contains(t, output, "info  gradleExecuteBuild - running command: gradle tasks") | ||||
| 	assert.Contains(t, output, "gradle cyclonedxBom") | ||||
| 	assert.Contains(t, output, "info  gradleExecuteBuild - running command: gradle cyclonedxBom") | ||||
| 	assert.Contains(t, output, "info  gradleExecuteBuild - running command: gradle build") | ||||
| 	assert.Contains(t, output, "info  gradleExecuteBuild - BUILD SUCCESSFUL") | ||||
| 	assert.Contains(t, output, "info  gradleExecuteBuild - SUCCESS") | ||||
|   | ||||
							
								
								
									
										6
									
								
								integration/testdata/TestGradleIntegration/java-project/.pipeline/config.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								integration/testdata/TestGradleIntegration/java-project/.pipeline/config.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| general: | ||||
|   createBOM: true | ||||
|  | ||||
| steps: | ||||
|   gradleExecuteBuild: | ||||
|     useWrapper: true | ||||
							
								
								
									
										
											BIN
										
									
								
								integration/testdata/TestGradleIntegration/java-project/gradle/wrapper/gradle-wrapper.jar
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								integration/testdata/TestGradleIntegration/java-project/gradle/wrapper/gradle-wrapper.jar
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| @@ -0,0 +1,5 @@ | ||||
| distributionBase=GRADLE_USER_HOME | ||||
| distributionPath=wrapper/dists | ||||
| distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.2-bin.zip | ||||
| zipStoreBase=GRADLE_USER_HOME | ||||
| zipStorePath=wrapper/dists | ||||
							
								
								
									
										233
									
								
								integration/testdata/TestGradleIntegration/java-project/gradlew
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										233
									
								
								integration/testdata/TestGradleIntegration/java-project/gradlew
									
									
									
									
										vendored
									
									
										Executable file
									
								
							| @@ -0,0 +1,233 @@ | ||||
| #!/bin/sh | ||||
|  | ||||
| # | ||||
| # Copyright © 2015-2021 the original authors. | ||||
| # | ||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| # you may not use this file except in compliance with the License. | ||||
| # You may obtain a copy of the License at | ||||
| # | ||||
| #      https://www.apache.org/licenses/LICENSE-2.0 | ||||
| # | ||||
| # Unless required by applicable law or agreed to in writing, software | ||||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
| # | ||||
|  | ||||
| ############################################################################## | ||||
| # | ||||
| #   Gradle start up script for POSIX generated by Gradle. | ||||
| # | ||||
| #   Important for running: | ||||
| # | ||||
| #   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is | ||||
| #       noncompliant, but you have some other compliant shell such as ksh or | ||||
| #       bash, then to run this script, type that shell name before the whole | ||||
| #       command line, like: | ||||
| # | ||||
| #           ksh Gradle | ||||
| # | ||||
| #       Busybox and similar reduced shells will NOT work, because this script | ||||
| #       requires all of these POSIX shell features: | ||||
| #         * functions; | ||||
| #         * expansions «$var», «${var}», «${var:-default}», «${var+SET}», | ||||
| #           «${var#prefix}», «${var%suffix}», and «$( cmd )»; | ||||
| #         * compound commands having a testable exit status, especially «case»; | ||||
| #         * various built-in commands including «command», «set», and «ulimit». | ||||
| # | ||||
| #   Important for patching: | ||||
| # | ||||
| #   (2) This script targets any POSIX shell, so it avoids extensions provided | ||||
| #       by Bash, Ksh, etc; in particular arrays are avoided. | ||||
| # | ||||
| #       The "traditional" practice of packing multiple parameters into a | ||||
| #       space-separated string is a well documented source of bugs and security | ||||
| #       problems, so this is (mostly) avoided, by progressively accumulating | ||||
| #       options in "$@", and eventually passing that to Java. | ||||
| # | ||||
| #       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, | ||||
| #       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; | ||||
| #       see the in-line comments for details. | ||||
| # | ||||
| #       There are tweaks for specific operating systems such as AIX, CygWin, | ||||
| #       Darwin, MinGW, and NonStop. | ||||
| # | ||||
| #   (3) This script is generated from the Groovy template | ||||
| #       within the Gradle project. | ||||
| # | ||||
| #       You can find Gradle at https://github.com/gradle/gradle/. | ||||
| # | ||||
| ############################################################################## | ||||
|  | ||||
| # Attempt to set APP_HOME | ||||
|  | ||||
| # Resolve links: $0 may be a link | ||||
| app_path=$0 | ||||
|  | ||||
| # Need this for daisy-chained symlinks. | ||||
| while | ||||
|     APP_HOME=${app_path%"${app_path##*/}"}  # leaves a trailing /; empty if no leading path | ||||
|     [ -h "$app_path" ] | ||||
| do | ||||
|     ls=$( ls -ld "$app_path" ) | ||||
|     link=${ls#*' -> '} | ||||
|     case $link in             #( | ||||
|       /*)   app_path=$link ;; #( | ||||
|       *)    app_path=$APP_HOME$link ;; | ||||
|     esac | ||||
| done | ||||
|  | ||||
| APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit | ||||
|  | ||||
| APP_NAME="Gradle" | ||||
| APP_BASE_NAME=${0##*/} | ||||
|  | ||||
| # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | ||||
| DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' | ||||
|  | ||||
| # Use the maximum available, or set MAX_FD != -1 to use that value. | ||||
| MAX_FD=maximum | ||||
|  | ||||
| warn () { | ||||
|     echo "$*" | ||||
| } >&2 | ||||
|  | ||||
| die () { | ||||
|     echo | ||||
|     echo "$*" | ||||
|     echo | ||||
|     exit 1 | ||||
| } >&2 | ||||
|  | ||||
| # OS specific support (must be 'true' or 'false'). | ||||
| cygwin=false | ||||
| msys=false | ||||
| darwin=false | ||||
| nonstop=false | ||||
| case "$( uname )" in                #( | ||||
|   CYGWIN* )         cygwin=true  ;; #( | ||||
|   Darwin* )         darwin=true  ;; #( | ||||
|   MSYS* | MINGW* )  msys=true    ;; #( | ||||
|   NONSTOP* )        nonstop=true ;; | ||||
| esac | ||||
|  | ||||
| CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar | ||||
|  | ||||
|  | ||||
| # Determine the Java command to use to start the JVM. | ||||
| if [ -n "$JAVA_HOME" ] ; then | ||||
|     if [ -x "$JAVA_HOME/jre/sh/java" ] ; then | ||||
|         # IBM's JDK on AIX uses strange locations for the executables | ||||
|         JAVACMD=$JAVA_HOME/jre/sh/java | ||||
|     else | ||||
|         JAVACMD=$JAVA_HOME/bin/java | ||||
|     fi | ||||
|     if [ ! -x "$JAVACMD" ] ; then | ||||
|         die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME | ||||
|  | ||||
| Please set the JAVA_HOME variable in your environment to match the | ||||
| location of your Java installation." | ||||
|     fi | ||||
| else | ||||
|     JAVACMD=java | ||||
|     which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. | ||||
|  | ||||
| Please set the JAVA_HOME variable in your environment to match the | ||||
| location of your Java installation." | ||||
| fi | ||||
|  | ||||
| # Increase the maximum file descriptors if we can. | ||||
| if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then | ||||
|     case $MAX_FD in #( | ||||
|       max*) | ||||
|         MAX_FD=$( ulimit -H -n ) || | ||||
|             warn "Could not query maximum file descriptor limit" | ||||
|     esac | ||||
|     case $MAX_FD in  #( | ||||
|       '' | soft) :;; #( | ||||
|       *) | ||||
|         ulimit -n "$MAX_FD" || | ||||
|             warn "Could not set maximum file descriptor limit to $MAX_FD" | ||||
|     esac | ||||
| fi | ||||
|  | ||||
| # Collect all arguments for the java command, stacking in reverse order: | ||||
| #   * args from the command line | ||||
| #   * the main class name | ||||
| #   * -classpath | ||||
| #   * -D...appname settings | ||||
| #   * --module-path (only if needed) | ||||
| #   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. | ||||
|  | ||||
| # For Cygwin or MSYS, switch paths to Windows format before running java | ||||
| if "$cygwin" || "$msys" ; then | ||||
|     APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) | ||||
|     CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) | ||||
|  | ||||
|     JAVACMD=$( cygpath --unix "$JAVACMD" ) | ||||
|  | ||||
|     # Now convert the arguments - kludge to limit ourselves to /bin/sh | ||||
|     for arg do | ||||
|         if | ||||
|             case $arg in                                #( | ||||
|               -*)   false ;;                            # don't mess with options #( | ||||
|               /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath | ||||
|                     [ -e "$t" ] ;;                      #( | ||||
|               *)    false ;; | ||||
|             esac | ||||
|         then | ||||
|             arg=$( cygpath --path --ignore --mixed "$arg" ) | ||||
|         fi | ||||
|         # Roll the args list around exactly as many times as the number of | ||||
|         # args, so each arg winds up back in the position where it started, but | ||||
|         # possibly modified. | ||||
|         # | ||||
|         # NB: a `for` loop captures its iteration list before it begins, so | ||||
|         # changing the positional parameters here affects neither the number of | ||||
|         # iterations, nor the values presented in `arg`. | ||||
|         shift                   # remove old arg | ||||
|         set -- "$@" "$arg"      # push replacement arg | ||||
|     done | ||||
| fi | ||||
|  | ||||
| # Collect all arguments for the java command; | ||||
| #   * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of | ||||
| #     shell script including quotes and variable substitutions, so put them in | ||||
| #     double quotes to make sure that they get re-expanded; and | ||||
| #   * put everything else in single quotes, so that it's not re-expanded. | ||||
|  | ||||
| set -- \ | ||||
|         "-Dorg.gradle.appname=$APP_BASE_NAME" \ | ||||
|         -classpath "$CLASSPATH" \ | ||||
|         org.gradle.wrapper.GradleWrapperMain \ | ||||
|         "$@" | ||||
|  | ||||
| # Use "xargs" to parse quoted args. | ||||
| # | ||||
| # With -n1 it outputs one arg per line, with the quotes and backslashes removed. | ||||
| # | ||||
| # In Bash we could simply go: | ||||
| # | ||||
| #   readarray ARGS < <( xargs -n1 <<<"$var" ) && | ||||
| #   set -- "${ARGS[@]}" "$@" | ||||
| # | ||||
| # but POSIX shell has neither arrays nor command substitution, so instead we | ||||
| # post-process each arg (as a line of input to sed) to backslash-escape any | ||||
| # character that might be a shell metacharacter, then use eval to reverse | ||||
| # that process (while maintaining the separation between arguments), and wrap | ||||
| # the whole thing up as a single "set" statement. | ||||
| # | ||||
| # This will of course break if any of these variables contains a newline or | ||||
| # an unmatched quote. | ||||
| # | ||||
|  | ||||
| eval "set -- $( | ||||
|         printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | | ||||
|         xargs -n1 | | ||||
|         sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | | ||||
|         tr '\n' ' ' | ||||
|     )" '"$@"' | ||||
|  | ||||
| exec "$JAVACMD" "$@" | ||||
							
								
								
									
										89
									
								
								integration/testdata/TestGradleIntegration/java-project/gradlew.bat
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								integration/testdata/TestGradleIntegration/java-project/gradlew.bat
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,89 @@ | ||||
| @rem | ||||
| @rem Copyright 2015 the original author or authors. | ||||
| @rem | ||||
| @rem Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| @rem you may not use this file except in compliance with the License. | ||||
| @rem You may obtain a copy of the License at | ||||
| @rem | ||||
| @rem      https://www.apache.org/licenses/LICENSE-2.0 | ||||
| @rem | ||||
| @rem Unless required by applicable law or agreed to in writing, software | ||||
| @rem distributed under the License is distributed on an "AS IS" BASIS, | ||||
| @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| @rem See the License for the specific language governing permissions and | ||||
| @rem limitations under the License. | ||||
| @rem | ||||
|  | ||||
| @if "%DEBUG%" == "" @echo off | ||||
| @rem ########################################################################## | ||||
| @rem | ||||
| @rem  Gradle startup script for Windows | ||||
| @rem | ||||
| @rem ########################################################################## | ||||
|  | ||||
| @rem Set local scope for the variables with windows NT shell | ||||
| if "%OS%"=="Windows_NT" setlocal | ||||
|  | ||||
| set DIRNAME=%~dp0 | ||||
| if "%DIRNAME%" == "" set DIRNAME=. | ||||
| set APP_BASE_NAME=%~n0 | ||||
| set APP_HOME=%DIRNAME% | ||||
|  | ||||
| @rem Resolve any "." and ".." in APP_HOME to make it shorter. | ||||
| for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi | ||||
|  | ||||
| @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | ||||
| set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" | ||||
|  | ||||
| @rem Find java.exe | ||||
| if defined JAVA_HOME goto findJavaFromJavaHome | ||||
|  | ||||
| set JAVA_EXE=java.exe | ||||
| %JAVA_EXE% -version >NUL 2>&1 | ||||
| if "%ERRORLEVEL%" == "0" goto execute | ||||
|  | ||||
| echo. | ||||
| echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. | ||||
| echo. | ||||
| echo Please set the JAVA_HOME variable in your environment to match the | ||||
| echo location of your Java installation. | ||||
|  | ||||
| goto fail | ||||
|  | ||||
| :findJavaFromJavaHome | ||||
| set JAVA_HOME=%JAVA_HOME:"=% | ||||
| set JAVA_EXE=%JAVA_HOME%/bin/java.exe | ||||
|  | ||||
| if exist "%JAVA_EXE%" goto execute | ||||
|  | ||||
| echo. | ||||
| echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% | ||||
| echo. | ||||
| echo Please set the JAVA_HOME variable in your environment to match the | ||||
| echo location of your Java installation. | ||||
|  | ||||
| goto fail | ||||
|  | ||||
| :execute | ||||
| @rem Setup the command line | ||||
|  | ||||
| set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar | ||||
|  | ||||
|  | ||||
| @rem Execute Gradle | ||||
| "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* | ||||
|  | ||||
| :end | ||||
| @rem End local scope for the variables with windows NT shell | ||||
| if "%ERRORLEVEL%"=="0" goto mainEnd | ||||
|  | ||||
| :fail | ||||
| rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of | ||||
| rem the _cmd.exe /c_ return code! | ||||
| if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 | ||||
| exit /b 1 | ||||
|  | ||||
| :mainEnd | ||||
| if "%OS%"=="Windows_NT" endlocal | ||||
|  | ||||
| :omega | ||||
| @@ -2,133 +2,86 @@ package gradle | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
| 	"text/template" | ||||
|  | ||||
| 	"github.com/SAP/jenkins-library/pkg/log" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	exec                  = "gradle" | ||||
| 	bomTaskName           = "cyclonedxBom" | ||||
| 	gradleExecutable  = "gradle" | ||||
| 	gradlewExecutable = "./gradlew" | ||||
|  | ||||
| 	groovyBuildScriptName = "build.gradle" | ||||
| 	kotlinBuildScriptName = "build.gradle.kts" | ||||
| 	createBOMScriptName   = "cyclonedx.gradle" | ||||
| 	publishInitScriptName = "maven-publish.gradle" | ||||
| 	initScriptName        = "initScript.gradle.tmp" | ||||
| ) | ||||
|  | ||||
| const publishInitScriptContentTemplate = ` | ||||
| rootProject { | ||||
|     apply plugin: 'maven-publish' | ||||
|     apply plugin: 'java' | ||||
|  | ||||
|     publishing { | ||||
|         publications { | ||||
|             maven(MavenPublication) { | ||||
|                 versionMapping { | ||||
|                     usage('java-api') { | ||||
|                         fromResolutionOf('runtimeClasspath') | ||||
|                     } | ||||
|                     usage('java-runtime') { | ||||
|                         fromResolutionResult() | ||||
|                     } | ||||
|                 } | ||||
| 				{{- if .ArtifactGroupID}} | ||||
| 				groupId = '{{.ArtifactGroupID}}' | ||||
| 				{{- end }} | ||||
| 				{{- if .ArtifactID}} | ||||
| 				artifactId = '{{.ArtifactID}}' | ||||
| 				{{- end }} | ||||
| 				{{- if .ArtifactVersion}} | ||||
| 				version = '{{.ArtifactVersion}}' | ||||
| 				{{- end }} | ||||
|                 from components.java | ||||
|             } | ||||
|         } | ||||
|         repositories { | ||||
|             maven { | ||||
|                 credentials { | ||||
|                     username = "{{.RepositoryUsername}}" | ||||
|                     password = "{{.RepositoryPassword}}" | ||||
|                 } | ||||
|                 url = "{{.RepositoryURL}}" | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| ` | ||||
|  | ||||
| const bomInitScriptContent = ` | ||||
| initscript { | ||||
|   repositories { | ||||
|     mavenCentral() | ||||
|     maven { | ||||
|       url "https://plugins.gradle.org/m2/" | ||||
|     } | ||||
|   } | ||||
|   dependencies { | ||||
|     classpath "com.cyclonedx:cyclonedx-gradle-plugin:1.5.0" | ||||
|   } | ||||
| } | ||||
|  | ||||
| rootProject { | ||||
|     apply plugin: 'java' | ||||
|     apply plugin: 'maven' | ||||
|     apply plugin: org.cyclonedx.gradle.CycloneDxPlugin | ||||
| } | ||||
| ` | ||||
|  | ||||
| type Utils interface { | ||||
| 	Stdout(out io.Writer) | ||||
| 	Stderr(err io.Writer) | ||||
| 	RunExecutable(e string, p ...string) error | ||||
|  | ||||
| 	DownloadFile(url, filename string, header http.Header, cookies []*http.Cookie) error | ||||
| 	Glob(pattern string) (matches []string, err error) | ||||
| 	FileExists(filename string) (bool, error) | ||||
| 	Copy(src, dest string) (int64, error) | ||||
| 	MkdirAll(path string, perm os.FileMode) error | ||||
| 	FileWrite(path string, content []byte, perm os.FileMode) error | ||||
| 	FileRead(path string) ([]byte, error) | ||||
| 	FileRemove(path string) error | ||||
| } | ||||
|  | ||||
| // ExecuteOptions are used by Execute() to construct the Gradle command line. | ||||
| type ExecuteOptions struct { | ||||
| 	BuildGradlePath    string `json:"path,omitempty"` | ||||
| 	Task               string `json:"task,omitempty"` | ||||
| 	CreateBOM          bool   `json:"createBOM,omitempty"` | ||||
| 	ReturnStdout       bool   `json:"returnStdout,omitempty"` | ||||
| 	Publish            bool   `json:"publish,omitempty"` | ||||
| 	ArtifactVersion    string `json:"artifactVersion,omitempty"` | ||||
| 	ArtifactGroupID    string `json:"artifactGroupId,omitempty"` | ||||
| 	ArtifactID         string `json:"artifactId,omitempty"` | ||||
| 	RepositoryURL      string `json:"repositoryUrl,omitempty"` | ||||
| 	RepositoryPassword string `json:"repositoryPassword,omitempty"` | ||||
| 	RepositoryUsername string `json:"repositoryUsername,omitempty"` | ||||
| 	BuildGradlePath   string            `json:"path,omitempty"` | ||||
| 	Task              string            `json:"task,omitempty"` | ||||
| 	InitScriptContent string            `json:"initScriptContent,omitempty"` | ||||
| 	UseWrapper        bool              `json:"useWrapper,omitempty"` | ||||
| 	ProjectProperties map[string]string `json:"projectProperties,omitempty"` | ||||
| 	setInitScript     bool | ||||
| } | ||||
|  | ||||
| func Execute(options *ExecuteOptions, utils Utils) error { | ||||
| 	groovyBuildScriptExists, err := utils.FileExists(filepath.Join(options.BuildGradlePath, groovyBuildScriptName)) | ||||
| func Execute(options *ExecuteOptions, utils Utils) (string, error) { | ||||
| 	stdOutBuf := new(bytes.Buffer) | ||||
| 	utils.Stdout(io.MultiWriter(log.Writer(), stdOutBuf)) | ||||
| 	utils.Stderr(log.Writer()) | ||||
|  | ||||
| 	_, err := searchBuildScript([]string{ | ||||
| 		filepath.Join(options.BuildGradlePath, groovyBuildScriptName), | ||||
| 		filepath.Join(options.BuildGradlePath, kotlinBuildScriptName), | ||||
| 	}, utils.FileExists) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("failed to check if file exists: %v", err) | ||||
| 	} | ||||
| 	kotlinBuildScriptExists, err := utils.FileExists(filepath.Join(options.BuildGradlePath, kotlinBuildScriptName)) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("failed to check if file exists: %v", err) | ||||
| 	} | ||||
| 	if !groovyBuildScriptExists && !kotlinBuildScriptExists { | ||||
| 		return fmt.Errorf("the specified gradle build script could not be found") | ||||
| 		return "", fmt.Errorf("the specified gradle build script could not be found: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	if options.CreateBOM { | ||||
| 		if err := createBOM(options, utils); err != nil { | ||||
| 			return fmt.Errorf("failed to create BOM: %v", err) | ||||
| 	exec := gradleExecutable | ||||
| 	if options.UseWrapper { | ||||
| 		wrapperExists, err := utils.FileExists("gradlew") | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
| 		if !wrapperExists { | ||||
| 			return "", errors.New("gradle wrapper not found") | ||||
| 		} | ||||
| 		exec = gradlewExecutable | ||||
| 	} | ||||
| 	log.Entry().Infof("All commands will be executed with the '%s' tool", exec) | ||||
|  | ||||
| 	if options.InitScriptContent != "" { | ||||
| 		parameters := []string{"tasks"} | ||||
| 		if options.BuildGradlePath != "" { | ||||
| 			parameters = append(parameters, "-p", options.BuildGradlePath) | ||||
| 		} | ||||
| 		if err := utils.RunExecutable(exec, parameters...); err != nil { | ||||
| 			return "", fmt.Errorf("failed list gradle tasks: %v", err) | ||||
| 		} | ||||
| 		if !strings.Contains(stdOutBuf.String(), options.Task) { | ||||
| 			err := utils.FileWrite(initScriptName, []byte(options.InitScriptContent), 0644) | ||||
| 			if err != nil { | ||||
| 				return "", fmt.Errorf("failed create init script: %v", err) | ||||
| 			} | ||||
| 			defer utils.FileRemove(initScriptName) | ||||
| 			options.setInitScript = true | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @@ -138,16 +91,10 @@ func Execute(options *ExecuteOptions, utils Utils) error { | ||||
| 	if err != nil { | ||||
| 		log.SetErrorCategory(log.ErrorBuild) | ||||
| 		commandLine := append([]string{exec}, parameters...) | ||||
| 		return fmt.Errorf("failed to run executable, command: '%s', error: %v", commandLine, err) | ||||
| 		return "", fmt.Errorf("failed to run executable, command: '%s', error: %v", commandLine, err) | ||||
| 	} | ||||
|  | ||||
| 	if options.Publish { | ||||
| 		if err := publish(options, utils); err != nil { | ||||
| 			return fmt.Errorf("failed to publish artifacts to staging repository: %v", err) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| 	return string(stdOutBuf.Bytes()), nil | ||||
| } | ||||
|  | ||||
| func getParametersFromOptions(options *ExecuteOptions) []string { | ||||
| @@ -161,82 +108,31 @@ func getParametersFromOptions(options *ExecuteOptions) []string { | ||||
| 		parameters = append(parameters, "-p", options.BuildGradlePath) | ||||
| 	} | ||||
|  | ||||
| 	for k, v := range options.ProjectProperties { | ||||
| 		parameters = append(parameters, fmt.Sprintf("-P%s=%s", k, v)) | ||||
| 	} | ||||
|  | ||||
| 	if options.setInitScript { | ||||
| 		parameters = append(parameters, "--init-script", initScriptName) | ||||
| 	} | ||||
|  | ||||
| 	return parameters | ||||
| } | ||||
|  | ||||
| func publish(options *ExecuteOptions, utils Utils) error { | ||||
| 	log.Entry().Info("Publishing artifact to staging repository...") | ||||
| 	if len(options.RepositoryURL) == 0 { | ||||
| 		return fmt.Errorf("there's no target repository for binary publishing configured") | ||||
| 	} | ||||
| 	publishInitScriptContent, err := getPublishInitScriptContent(options) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("failed to get init script content: %v", err) | ||||
| 	} | ||||
| 	err = utils.FileWrite(filepath.Join(options.BuildGradlePath, publishInitScriptName), []byte(publishInitScriptContent), 0644) | ||||
| 	if err != nil { | ||||
| 		return fmt.Errorf("failed create init script: %v", err) | ||||
| 	} | ||||
| 	defer utils.FileRemove(filepath.Join(options.BuildGradlePath, publishInitScriptName)) | ||||
|  | ||||
| 	parameters := []string{"--init-script", filepath.Join(options.BuildGradlePath, publishInitScriptName), "--info", "publish"} | ||||
| 	if options.BuildGradlePath != "" { | ||||
| 		parameters = append(parameters, "-p", options.BuildGradlePath) | ||||
| 	} | ||||
| 	if err := utils.RunExecutable(exec, parameters...); err != nil { | ||||
| 		return fmt.Errorf("publishing failed: %v", err) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func getPublishInitScriptContent(options *ExecuteOptions) (string, error) { | ||||
| 	tmpl, err := template.New("resources").Parse(publishInitScriptContentTemplate) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	var generatedCode bytes.Buffer | ||||
| 	err = tmpl.Execute(&generatedCode, options) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	return string(generatedCode.Bytes()), nil | ||||
| } | ||||
|  | ||||
| // CreateBOM generates BOM file using CycloneDX | ||||
| func createBOM(options *ExecuteOptions, utils Utils) error { | ||||
| 	log.Entry().Info("BOM creation...") | ||||
| 	// check if gradle task cyclonedxBom exists | ||||
| 	stdOutBuf := new(bytes.Buffer) | ||||
| 	stdOut := log.Writer() | ||||
| 	stdOut = io.MultiWriter(stdOut, stdOutBuf) | ||||
| 	utils.Stdout(stdOut) | ||||
| 	parameters := []string{"tasks"} | ||||
| 	if options.BuildGradlePath != "" { | ||||
| 		parameters = append(parameters, "-p", options.BuildGradlePath) | ||||
| 	} | ||||
| 	if err := utils.RunExecutable(exec, parameters...); err != nil { | ||||
| 		return fmt.Errorf("failed list gradle tasks: %v", err) | ||||
| 	} | ||||
| 	if strings.Contains(stdOutBuf.String(), bomTaskName) { | ||||
| 		if err := utils.RunExecutable(exec, bomTaskName); err != nil { | ||||
| 			return fmt.Errorf("BOM creation failed: %v", err) | ||||
| 		} | ||||
| 	} else { | ||||
| 		err := utils.FileWrite(filepath.Join(options.BuildGradlePath, createBOMScriptName), []byte(bomInitScriptContent), 0644) | ||||
| func searchBuildScript(supported []string, existsFunc func(string) (bool, error)) (string, error) { | ||||
| 	var descriptor string | ||||
| 	for _, f := range supported { | ||||
| 		exists, err := existsFunc(f) | ||||
| 		if err != nil { | ||||
| 			return fmt.Errorf("failed create init script: %v", err) | ||||
| 			return "", err | ||||
| 		} | ||||
| 		defer utils.FileRemove(filepath.Join(options.BuildGradlePath, createBOMScriptName)) | ||||
| 		parameters := []string{"--init-script", filepath.Join(options.BuildGradlePath, createBOMScriptName), bomTaskName} | ||||
| 		if options.BuildGradlePath != "" { | ||||
| 			parameters = append(parameters, "-p", options.BuildGradlePath) | ||||
| 		} | ||||
| 		if err := utils.RunExecutable(exec, parameters...); err != nil { | ||||
| 			return fmt.Errorf("BOM creation failed: %v", err) | ||||
| 		if exists { | ||||
| 			descriptor = f | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| 	if len(descriptor) == 0 { | ||||
| 		return "", fmt.Errorf("no build script available, supported: %v", supported) | ||||
| 	} | ||||
| 	return descriptor, nil | ||||
| } | ||||
|   | ||||
| @@ -2,8 +2,6 @@ package gradle | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"os" | ||||
|  | ||||
| 	"github.com/SAP/jenkins-library/pkg/mock" | ||||
| @@ -40,33 +38,119 @@ func (m *MockUtils) FileRemove(path string) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (m *MockUtils) DownloadFile(url, filename string, header http.Header, cookies []*http.Cookie) error { | ||||
| 	return fmt.Errorf("not implemented") | ||||
| } | ||||
|  | ||||
| func TestExecute(t *testing.T) { | ||||
| 	t.Run("success - gradle build", func(t *testing.T) { | ||||
| 	t.Run("success - run command use gradle tool", func(t *testing.T) { | ||||
| 		utils := &MockUtils{ | ||||
| 			FilesMock:      &mock.FilesMock{}, | ||||
| 			ExecMockRunner: &mock.ExecMockRunner{}, | ||||
| 			existingFiles:  []string{"path/to/build.gradle"}, | ||||
| 		} | ||||
| 		opts := ExecuteOptions{ | ||||
| 			BuildGradlePath: "path/to", | ||||
| 			Task:            "build", | ||||
| 			CreateBOM:       false, | ||||
| 			BuildGradlePath:   "path/to", | ||||
| 			Task:              "build", | ||||
| 			InitScriptContent: "", | ||||
| 			UseWrapper:        false, | ||||
| 			ProjectProperties: map[string]string{"propName": "propValue"}, | ||||
| 		} | ||||
|  | ||||
| 		err := Execute(&opts, utils) | ||||
| 		_, err := Execute(&opts, utils) | ||||
| 		assert.NoError(t, err) | ||||
|  | ||||
| 		assert.Equal(t, 1, len(utils.Calls)) | ||||
| 		assert.Equal(t, mock.ExecCall{Exec: "gradle", Params: []string{"build", "-p", "path/to"}}, utils.Calls[0]) | ||||
| 		assert.Equal(t, mock.ExecCall{Exec: "gradle", Params: []string{"build", "-p", "path/to", "-PpropName=propValue"}}, utils.Calls[0]) | ||||
| 		assert.Equal(t, []string(nil), utils.writtenFiles) | ||||
| 		assert.Equal(t, []string(nil), utils.removedFiles) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("failed - gradle build", func(t *testing.T) { | ||||
| 	t.Run("success - run command use gradlew tool", func(t *testing.T) { | ||||
| 		utils := &MockUtils{ | ||||
| 			FilesMock:      &mock.FilesMock{}, | ||||
| 			ExecMockRunner: &mock.ExecMockRunner{}, | ||||
| 			existingFiles:  []string{"path/to/build.gradle", "gradlew"}, | ||||
| 		} | ||||
| 		opts := ExecuteOptions{ | ||||
| 			BuildGradlePath:   "path/to", | ||||
| 			Task:              "build", | ||||
| 			InitScriptContent: "", | ||||
| 			UseWrapper:        true, | ||||
| 		} | ||||
|  | ||||
| 		_, err := Execute(&opts, utils) | ||||
| 		assert.NoError(t, err) | ||||
|  | ||||
| 		assert.Equal(t, 1, len(utils.Calls)) | ||||
| 		assert.Equal(t, mock.ExecCall{Exec: "./gradlew", Params: []string{"build", "-p", "path/to"}}, utils.Calls[0]) | ||||
| 		assert.Equal(t, []string(nil), utils.writtenFiles) | ||||
| 		assert.Equal(t, []string(nil), utils.removedFiles) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("use init script to apply plugin", func(t *testing.T) { | ||||
| 		utils := &MockUtils{ | ||||
| 			FilesMock:      &mock.FilesMock{}, | ||||
| 			ExecMockRunner: &mock.ExecMockRunner{}, | ||||
| 			existingFiles:  []string{"path/to/build.gradle.kts"}, | ||||
| 		} | ||||
| 		opts := ExecuteOptions{ | ||||
| 			BuildGradlePath:   "path/to", | ||||
| 			Task:              "build", | ||||
| 			InitScriptContent: "some content", | ||||
| 			UseWrapper:        false, | ||||
| 		} | ||||
|  | ||||
| 		_, err := Execute(&opts, utils) | ||||
| 		assert.NoError(t, err) | ||||
|  | ||||
| 		assert.Equal(t, 2, len(utils.Calls)) | ||||
| 		assert.Equal(t, mock.ExecCall{Exec: "gradle", Params: []string{"tasks", "-p", "path/to"}}, utils.Calls[0]) | ||||
| 		assert.Equal(t, mock.ExecCall{Execution: (*mock.Execution)(nil), Async: false, Exec: "gradle", Params: []string{"build", "-p", "path/to", "--init-script", "initScript.gradle.tmp"}}, utils.Calls[1]) | ||||
| 		assert.Equal(t, []string{"initScript.gradle.tmp"}, utils.writtenFiles) | ||||
| 		assert.Equal(t, []string{"initScript.gradle.tmp"}, utils.removedFiles) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("failed - use init script to apply plugin", func(t *testing.T) { | ||||
| 		utils := &MockUtils{ | ||||
| 			FilesMock: &mock.FilesMock{}, | ||||
| 			ExecMockRunner: &mock.ExecMockRunner{ | ||||
| 				ShouldFailOnCommand: map[string]error{"gradle tasks -p path/to": errors.New("failed to get tasks")}, | ||||
| 			}, | ||||
| 			existingFiles: []string{"path/to/build.gradle.kts"}, | ||||
| 		} | ||||
| 		opts := ExecuteOptions{ | ||||
| 			BuildGradlePath:   "path/to", | ||||
| 			Task:              "build", | ||||
| 			InitScriptContent: "some content", | ||||
| 			UseWrapper:        false, | ||||
| 		} | ||||
|  | ||||
| 		_, err := Execute(&opts, utils) | ||||
| 		assert.Error(t, err) | ||||
| 		assert.Contains(t, err.Error(), "failed to get tasks") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("use init script to apply an existing plugin", func(t *testing.T) { | ||||
| 		utils := &MockUtils{ | ||||
| 			FilesMock:      &mock.FilesMock{}, | ||||
| 			ExecMockRunner: &mock.ExecMockRunner{}, | ||||
| 			existingFiles:  []string{"path/to/build.gradle.kts"}, | ||||
| 		} | ||||
| 		utils.StdoutReturn = map[string]string{"gradle tasks -p path/to": "createBom"} | ||||
| 		opts := ExecuteOptions{ | ||||
| 			BuildGradlePath:   "path/to", | ||||
| 			Task:              "createBom", | ||||
| 			InitScriptContent: "some content", | ||||
| 			UseWrapper:        false, | ||||
| 		} | ||||
|  | ||||
| 		_, err := Execute(&opts, utils) | ||||
| 		assert.NoError(t, err) | ||||
|  | ||||
| 		assert.Equal(t, 2, len(utils.Calls)) | ||||
| 		assert.Equal(t, mock.ExecCall{Exec: "gradle", Params: []string{"tasks", "-p", "path/to"}}, utils.Calls[0]) | ||||
| 		assert.Equal(t, mock.ExecCall{Execution: (*mock.Execution)(nil), Async: false, Exec: "gradle", Params: []string{"createBom", "-p", "path/to"}}, utils.Calls[1]) | ||||
| 		assert.Equal(t, []string(nil), utils.writtenFiles) | ||||
| 		assert.Equal(t, []string(nil), utils.removedFiles) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("failed - run command", func(t *testing.T) { | ||||
| 		utils := &MockUtils{ | ||||
| 			FilesMock: &mock.FilesMock{}, | ||||
| 			ExecMockRunner: &mock.ExecMockRunner{ | ||||
| @@ -75,97 +159,53 @@ func TestExecute(t *testing.T) { | ||||
| 			existingFiles: []string{"path/to/build.gradle"}, | ||||
| 		} | ||||
| 		opts := ExecuteOptions{ | ||||
| 			BuildGradlePath: "path/to", | ||||
| 			Task:            "build", | ||||
| 			CreateBOM:       false, | ||||
| 			BuildGradlePath:   "path/to", | ||||
| 			Task:              "build", | ||||
| 			InitScriptContent: "", | ||||
| 			UseWrapper:        false, | ||||
| 		} | ||||
|  | ||||
| 		err := Execute(&opts, utils) | ||||
| 		_, err := Execute(&opts, utils) | ||||
| 		assert.Error(t, err) | ||||
| 		assert.Contains(t, err.Error(), "failed to build") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("success - bom creation", func(t *testing.T) { | ||||
| 	t.Run("failed - missing gradle build script", func(t *testing.T) { | ||||
| 		utils := &MockUtils{ | ||||
| 			FilesMock:      &mock.FilesMock{}, | ||||
| 			ExecMockRunner: &mock.ExecMockRunner{}, | ||||
| 			existingFiles:  []string{"build.gradle"}, | ||||
| 			existingFiles:  []string{}, | ||||
| 		} | ||||
| 		opts := ExecuteOptions{ | ||||
| 			Task:      "build", | ||||
| 			CreateBOM: true, | ||||
| 			BuildGradlePath:   "path/to", | ||||
| 			Task:              "build", | ||||
| 			InitScriptContent: "", | ||||
| 			UseWrapper:        false, | ||||
| 		} | ||||
|  | ||||
| 		err := Execute(&opts, utils) | ||||
| 		assert.NoError(t, err) | ||||
|  | ||||
| 		assert.Equal(t, 3, len(utils.Calls)) | ||||
| 		assert.Equal(t, mock.ExecCall{Exec: "gradle", Params: []string{"tasks"}}, utils.Calls[0]) | ||||
| 		assert.Equal(t, mock.ExecCall{Exec: "gradle", Params: []string{"--init-script", "cyclonedx.gradle", "cyclonedxBom"}}, utils.Calls[1]) | ||||
| 		assert.Equal(t, mock.ExecCall{Exec: "gradle", Params: []string{"build"}}, utils.Calls[2]) | ||||
| 		assert.Equal(t, []string{"cyclonedx.gradle"}, utils.writtenFiles) | ||||
| 		assert.Equal(t, []string{"cyclonedx.gradle"}, utils.removedFiles) | ||||
| 		_, err := Execute(&opts, utils) | ||||
| 		assert.Error(t, err) | ||||
| 		assert.Contains(t, err.Error(), "the specified gradle build script could not be found") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("failed - bom creation", func(t *testing.T) { | ||||
| 		utils := &MockUtils{ | ||||
| 			FilesMock: &mock.FilesMock{}, | ||||
| 			ExecMockRunner: &mock.ExecMockRunner{ | ||||
| 				ShouldFailOnCommand: map[string]error{"gradle --init-script cyclonedx.gradle cyclonedxBom": errors.New("failed to create BOM")}, | ||||
| 			}, | ||||
| 			existingFiles: []string{"build.gradle"}, | ||||
| 		} | ||||
| 		opts := ExecuteOptions{ | ||||
| 			Task:      "build", | ||||
| 			CreateBOM: true, | ||||
| 		} | ||||
|  | ||||
| 		err := Execute(&opts, utils) | ||||
| 		assert.Contains(t, err.Error(), "failed to create BOM") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("success - publish to staging repository", func(t *testing.T) { | ||||
| 	t.Run("success - should return stdOut", func(t *testing.T) { | ||||
| 		expectedOutput := "mocked output" | ||||
| 		utils := &MockUtils{ | ||||
| 			FilesMock:      &mock.FilesMock{}, | ||||
| 			ExecMockRunner: &mock.ExecMockRunner{}, | ||||
| 			existingFiles:  []string{"build.gradle"}, | ||||
| 			existingFiles:  []string{"path/to/build.gradle"}, | ||||
| 		} | ||||
| 		utils.StdoutReturn = map[string]string{"gradle build -p path/to": expectedOutput} | ||||
| 		opts := ExecuteOptions{ | ||||
| 			Task:               "build", | ||||
| 			Publish:            true, | ||||
| 			RepositoryURL:      "url", | ||||
| 			RepositoryPassword: "password", | ||||
| 			RepositoryUsername: "username", | ||||
| 			ArtifactVersion:    "1.1.0", | ||||
| 			BuildGradlePath:   "path/to", | ||||
| 			Task:              "build", | ||||
| 			InitScriptContent: "", | ||||
| 			UseWrapper:        false, | ||||
| 		} | ||||
|  | ||||
| 		err := Execute(&opts, utils) | ||||
| 		actualOutput, err := Execute(&opts, utils) | ||||
| 		assert.NoError(t, err) | ||||
|  | ||||
| 		assert.Equal(t, 2, len(utils.Calls)) | ||||
| 		assert.Equal(t, mock.ExecCall{Exec: "gradle", Params: []string{"build"}}, utils.Calls[0]) | ||||
| 		assert.Equal(t, mock.ExecCall{Exec: "gradle", Params: []string{"--init-script", "maven-publish.gradle", "--info", "publish"}}, utils.Calls[1]) | ||||
| 		assert.Equal(t, []string{"maven-publish.gradle"}, utils.writtenFiles) | ||||
| 		assert.Equal(t, []string{"maven-publish.gradle"}, utils.removedFiles) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("failed - publish to staging repository", func(t *testing.T) { | ||||
| 		utils := &MockUtils{ | ||||
| 			FilesMock: &mock.FilesMock{}, | ||||
| 			ExecMockRunner: &mock.ExecMockRunner{ | ||||
| 				ShouldFailOnCommand: map[string]error{"gradle --init-script maven-publish.gradle --info publish": errors.New("failed to publish artifacts")}, | ||||
| 			}, | ||||
| 			existingFiles: []string{"build.gradle"}, | ||||
| 		} | ||||
| 		opts := ExecuteOptions{ | ||||
| 			Task:               "build", | ||||
| 			Publish:            true, | ||||
| 			RepositoryURL:      "url", | ||||
| 			RepositoryPassword: "password", | ||||
| 			RepositoryUsername: "username", | ||||
| 			ArtifactVersion:    "1.1.0", | ||||
| 		} | ||||
|  | ||||
| 		err := Execute(&opts, utils) | ||||
| 		assert.Contains(t, err.Error(), "failed to publish artifacts") | ||||
| 		assert.Equal(t, expectedOutput, actualOutput) | ||||
| 	}) | ||||
| } | ||||
|   | ||||
| @@ -1,7 +1,6 @@ | ||||
| package versioning | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| @@ -9,6 +8,7 @@ import ( | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/SAP/jenkins-library/pkg/command" | ||||
| 	"github.com/SAP/jenkins-library/pkg/gradle" | ||||
| 	"github.com/SAP/jenkins-library/pkg/log" | ||||
| ) | ||||
|  | ||||
| @@ -21,6 +21,7 @@ type gradleExecRunner interface { | ||||
| // Gradle defines a maven artifact used for versioning | ||||
| type Gradle struct { | ||||
| 	execRunner     gradleExecRunner | ||||
| 	utils          gradle.Utils | ||||
| 	gradlePropsOut []byte | ||||
| 	path           string | ||||
| 	propertiesFile *PropertiesFile | ||||
| @@ -65,16 +66,16 @@ func (g *Gradle) initGetArtifact() error { | ||||
| 	} | ||||
|  | ||||
| 	if g.gradlePropsOut == nil { | ||||
| 		gradlePropsBuffer := &bytes.Buffer{} | ||||
| 		g.execRunner.Stdout(gradlePropsBuffer) | ||||
| 		var p []string | ||||
| 		p = append(p, "properties", "--no-daemon", "--console=plain", "-q") | ||||
| 		err := g.execRunner.RunExecutable("gradle", p...) | ||||
| 		gradleOptions := &gradle.ExecuteOptions{ | ||||
| 			Task:       "properties", | ||||
| 			UseWrapper: true, | ||||
| 		} | ||||
| 		stdOut, err := gradle.Execute(gradleOptions, g.utils) | ||||
| 		if err != nil { | ||||
| 			log.Entry().WithError(err).Errorf("failed to retrieve properties of the gradle project: %v", err) | ||||
| 			return err | ||||
| 		} | ||||
| 		g.gradlePropsOut = gradlePropsBuffer.Bytes() | ||||
| 		g.execRunner.Stdout(log.Writer()) | ||||
| 		g.gradlePropsOut = []byte(stdOut) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|   | ||||
| @@ -2,6 +2,9 @@ package versioning | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
|  | ||||
| 	"github.com/SAP/jenkins-library/pkg/piperutils" | ||||
| @@ -40,7 +43,18 @@ type Options struct { | ||||
|  | ||||
| // Utils defines the versioning operations for various build tools | ||||
| type Utils interface { | ||||
| 	maven.Utils | ||||
| 	Stdout(out io.Writer) | ||||
| 	Stderr(err io.Writer) | ||||
| 	RunExecutable(e string, p ...string) error | ||||
|  | ||||
| 	DownloadFile(url, filename string, header http.Header, cookies []*http.Cookie) error | ||||
| 	Glob(pattern string) (matches []string, err error) | ||||
| 	FileExists(filename string) (bool, error) | ||||
| 	Copy(src, dest string) (int64, error) | ||||
| 	MkdirAll(path string, perm os.FileMode) error | ||||
| 	FileWrite(path string, content []byte, perm os.FileMode) error | ||||
| 	FileRead(path string) ([]byte, error) | ||||
| 	FileRemove(path string) error | ||||
| } | ||||
|  | ||||
| type mvnRunner struct{} | ||||
| @@ -90,6 +104,7 @@ func GetArtifact(buildTool, buildDescriptorFilePath string, opts *Options, utils | ||||
| 		artifact = &Gradle{ | ||||
| 			path:         buildDescriptorFilePath, | ||||
| 			versionField: opts.VersionField, | ||||
| 			utils:        utils, | ||||
| 		} | ||||
| 	case "golang": | ||||
| 		if len(buildDescriptorFilePath) == 0 { | ||||
|   | ||||
| @@ -107,6 +107,14 @@ spec: | ||||
|         resourceRef: | ||||
|           - name: commonPipelineEnvironment | ||||
|             param: artifactId | ||||
|       - name: useWrapper | ||||
|         type: bool | ||||
|         description: If set to false all commands are executed using 'gradle', otherwise 'gradlew' is executed. | ||||
|         scope: | ||||
|           - STEPS | ||||
|           - STAGES | ||||
|           - PARAMETERS | ||||
|         default: false | ||||
|   outputs: | ||||
|     resources: | ||||
|       - name: reports | ||||
|   | ||||
		Reference in New Issue
	
	Block a user