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 
			
		
		
		
	gradleExecuteBuild initial commit (#3337)
* gradleExecuteBuild initial commit * fmt fixes for metadata_generated * flow updates, some tests were added * add gradle path alias, add stage scope to task parameter Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>
This commit is contained in:
		
							
								
								
									
										50
									
								
								cmd/gradleExecuteBuild.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								cmd/gradleExecuteBuild.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,50 @@ | ||||
| package cmd | ||||
|  | ||||
| import ( | ||||
| 	"github.com/SAP/jenkins-library/pkg/command" | ||||
| 	"github.com/SAP/jenkins-library/pkg/gradle" | ||||
| 	"github.com/SAP/jenkins-library/pkg/log" | ||||
| 	"github.com/SAP/jenkins-library/pkg/piperutils" | ||||
| 	"github.com/SAP/jenkins-library/pkg/telemetry" | ||||
| ) | ||||
|  | ||||
| type gradleExecuteBuildUtils interface { | ||||
| 	command.ExecRunner | ||||
| 	FileExists(filename string) (bool, error) | ||||
| } | ||||
|  | ||||
| type gradleExecuteBuildUtilsBundle struct { | ||||
| 	*command.Command | ||||
| 	*piperutils.Files | ||||
| } | ||||
|  | ||||
| func newGradleExecuteBuildUtils() gradleExecuteBuildUtils { | ||||
| 	utils := gradleExecuteBuildUtilsBundle{ | ||||
| 		Command: &command.Command{}, | ||||
| 		Files:   &piperutils.Files{}, | ||||
| 	} | ||||
| 	utils.Stdout(log.Writer()) | ||||
| 	utils.Stderr(log.Writer()) | ||||
| 	return &utils | ||||
| } | ||||
|  | ||||
| func gradleExecuteBuild(config gradleExecuteBuildOptions, telemetryData *telemetry.CustomData) { | ||||
| 	utils := newGradleExecuteBuildUtils() | ||||
| 	fileUtils := &piperutils.Files{} | ||||
| 	err := runGradleExecuteBuild(&config, telemetryData, utils, fileUtils) | ||||
| 	if err != nil { | ||||
| 		log.Entry().WithError(err).Fatal("step execution failed: %w", err) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func runGradleExecuteBuild(config *gradleExecuteBuildOptions, telemetryData *telemetry.CustomData, utils gradleExecuteBuildUtils, fileUtils piperutils.FileUtils) error { | ||||
| 	opt := &gradle.ExecuteOptions{BuildGradlePath: config.Path, Task: config.Task} | ||||
|  | ||||
| 	_, err := gradle.Execute(opt, utils, fileUtils) | ||||
| 	if err != nil { | ||||
| 		log.Entry().WithError(err).Errorln("build.gradle execution was failed: %w", err) | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										154
									
								
								cmd/gradleExecuteBuild_generated.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								cmd/gradleExecuteBuild_generated.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,154 @@ | ||||
| // Code generated by piper's step-generator. DO NOT EDIT. | ||||
|  | ||||
| package cmd | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/SAP/jenkins-library/pkg/config" | ||||
| 	"github.com/SAP/jenkins-library/pkg/log" | ||||
| 	"github.com/SAP/jenkins-library/pkg/splunk" | ||||
| 	"github.com/SAP/jenkins-library/pkg/telemetry" | ||||
| 	"github.com/SAP/jenkins-library/pkg/validation" | ||||
| 	"github.com/spf13/cobra" | ||||
| ) | ||||
|  | ||||
| type gradleExecuteBuildOptions struct { | ||||
| 	Path string `json:"path,omitempty"` | ||||
| 	Task string `json:"task,omitempty"` | ||||
| } | ||||
|  | ||||
| // GradleExecuteBuildCommand This step runs a gradle build command with parameters provided to the step. | ||||
| func GradleExecuteBuildCommand() *cobra.Command { | ||||
| 	const STEP_NAME = "gradleExecuteBuild" | ||||
|  | ||||
| 	metadata := gradleExecuteBuildMetadata() | ||||
| 	var stepConfig gradleExecuteBuildOptions | ||||
| 	var startTime time.Time | ||||
| 	var logCollector *log.CollectorHook | ||||
| 	var splunkClient *splunk.Splunk | ||||
| 	telemetryClient := &telemetry.Telemetry{} | ||||
|  | ||||
| 	var createGradleExecuteBuildCmd = &cobra.Command{ | ||||
| 		Use:   STEP_NAME, | ||||
| 		Short: "This step runs a gradle build command with parameters provided to the step.", | ||||
| 		Long:  `This step runs a gradle build command with parameters provided to the step.`, | ||||
| 		PreRunE: func(cmd *cobra.Command, _ []string) error { | ||||
| 			startTime = time.Now() | ||||
| 			log.SetStepName(STEP_NAME) | ||||
| 			log.SetVerbose(GeneralConfig.Verbose) | ||||
|  | ||||
| 			GeneralConfig.GitHubAccessTokens = ResolveAccessTokens(GeneralConfig.GitHubTokens) | ||||
|  | ||||
| 			path, _ := os.Getwd() | ||||
| 			fatalHook := &log.FatalHook{CorrelationID: GeneralConfig.CorrelationID, Path: path} | ||||
| 			log.RegisterHook(fatalHook) | ||||
|  | ||||
| 			err := PrepareConfig(cmd, &metadata, STEP_NAME, &stepConfig, config.OpenPiperFile) | ||||
| 			if err != nil { | ||||
| 				log.SetErrorCategory(log.ErrorConfiguration) | ||||
| 				return err | ||||
| 			} | ||||
|  | ||||
| 			if len(GeneralConfig.HookConfig.SentryConfig.Dsn) > 0 { | ||||
| 				sentryHook := log.NewSentryHook(GeneralConfig.HookConfig.SentryConfig.Dsn, GeneralConfig.CorrelationID) | ||||
| 				log.RegisterHook(&sentryHook) | ||||
| 			} | ||||
|  | ||||
| 			if len(GeneralConfig.HookConfig.SplunkConfig.Dsn) > 0 { | ||||
| 				splunkClient = &splunk.Splunk{} | ||||
| 				logCollector = &log.CollectorHook{CorrelationID: GeneralConfig.CorrelationID} | ||||
| 				log.RegisterHook(logCollector) | ||||
| 			} | ||||
|  | ||||
| 			validation, err := validation.New(validation.WithJSONNamesForStructFields(), validation.WithPredefinedErrorMessages()) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			if err = validation.ValidateStruct(stepConfig); err != nil { | ||||
| 				log.SetErrorCategory(log.ErrorConfiguration) | ||||
| 				return err | ||||
| 			} | ||||
|  | ||||
| 			return nil | ||||
| 		}, | ||||
| 		Run: func(_ *cobra.Command, _ []string) { | ||||
| 			stepTelemetryData := telemetry.CustomData{} | ||||
| 			stepTelemetryData.ErrorCode = "1" | ||||
| 			handler := func() { | ||||
| 				config.RemoveVaultSecretFiles() | ||||
| 				stepTelemetryData.Duration = fmt.Sprintf("%v", time.Since(startTime).Milliseconds()) | ||||
| 				stepTelemetryData.ErrorCategory = log.GetErrorCategory().String() | ||||
| 				stepTelemetryData.PiperCommitHash = GitCommit | ||||
| 				telemetryClient.SetData(&stepTelemetryData) | ||||
| 				telemetryClient.Send() | ||||
| 				if len(GeneralConfig.HookConfig.SplunkConfig.Dsn) > 0 { | ||||
| 					splunkClient.Send(telemetryClient.GetData(), logCollector) | ||||
| 				} | ||||
| 			} | ||||
| 			log.DeferExitHandler(handler) | ||||
| 			defer handler() | ||||
| 			telemetryClient.Initialize(GeneralConfig.NoTelemetry, STEP_NAME) | ||||
| 			if len(GeneralConfig.HookConfig.SplunkConfig.Dsn) > 0 { | ||||
| 				splunkClient.Initialize(GeneralConfig.CorrelationID, | ||||
| 					GeneralConfig.HookConfig.SplunkConfig.Dsn, | ||||
| 					GeneralConfig.HookConfig.SplunkConfig.Token, | ||||
| 					GeneralConfig.HookConfig.SplunkConfig.Index, | ||||
| 					GeneralConfig.HookConfig.SplunkConfig.SendLogs) | ||||
| 			} | ||||
| 			gradleExecuteBuild(stepConfig, &stepTelemetryData) | ||||
| 			stepTelemetryData.ErrorCode = "0" | ||||
| 			log.Entry().Info("SUCCESS") | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	addGradleExecuteBuildFlags(createGradleExecuteBuildCmd, &stepConfig) | ||||
| 	return createGradleExecuteBuildCmd | ||||
| } | ||||
|  | ||||
| func addGradleExecuteBuildFlags(cmd *cobra.Command, stepConfig *gradleExecuteBuildOptions) { | ||||
| 	cmd.Flags().StringVar(&stepConfig.Path, "path", os.Getenv("PIPER_path"), "Path to the folder with gradle.build file which should be executed.") | ||||
| 	cmd.Flags().StringVar(&stepConfig.Task, "task", `build`, "Gradle task that should be executed.") | ||||
|  | ||||
| } | ||||
|  | ||||
| // retrieve step metadata | ||||
| func gradleExecuteBuildMetadata() config.StepData { | ||||
| 	var theMetaData = config.StepData{ | ||||
| 		Metadata: config.StepMetadata{ | ||||
| 			Name:        "gradleExecuteBuild", | ||||
| 			Aliases:     []config.Alias{}, | ||||
| 			Description: "This step runs a gradle build command with parameters provided to the step.", | ||||
| 		}, | ||||
| 		Spec: config.StepSpec{ | ||||
| 			Inputs: config.StepInputs{ | ||||
| 				Parameters: []config.StepParameters{ | ||||
| 					{ | ||||
| 						Name:        "path", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"PARAMETERS", "STEPS"}, | ||||
| 						Type:        "string", | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{{Name: "buildGradlePath"}}, | ||||
| 						Default:     os.Getenv("PIPER_path"), | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "task", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:        "string", | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 						Default:     `build`, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			Containers: []config.Container{ | ||||
| 				{Name: "gradle", Image: "gradle:4.7.0-jdk8-alpine"}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 	return theMetaData | ||||
| } | ||||
							
								
								
									
										17
									
								
								cmd/gradleExecuteBuild_generated_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								cmd/gradleExecuteBuild_generated_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| package cmd | ||||
|  | ||||
| import ( | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| func TestGradleExecuteBuildCommand(t *testing.T) { | ||||
| 	t.Parallel() | ||||
|  | ||||
| 	testCmd := GradleExecuteBuildCommand() | ||||
|  | ||||
| 	// only high level testing performed - details are tested in step generation procedure | ||||
| 	assert.Equal(t, "gradleExecuteBuild", testCmd.Use, "command name incorrect") | ||||
|  | ||||
| } | ||||
							
								
								
									
										61
									
								
								cmd/gradleExecuteBuild_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								cmd/gradleExecuteBuild_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,61 @@ | ||||
| package cmd | ||||
|  | ||||
| import ( | ||||
| 	"strings" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
|  | ||||
| 	"github.com/SAP/jenkins-library/pkg/mock" | ||||
| ) | ||||
|  | ||||
| type gradleExecuteBuildMockUtils struct { | ||||
| 	*mock.ExecMockRunner | ||||
| 	*mock.FilesMock | ||||
| } | ||||
|  | ||||
| type gradleExecuteBuildFileMock struct { | ||||
| 	*mock.FilesMock | ||||
| 	fileReadContent map[string]string | ||||
| 	fileReadErr     map[string]error | ||||
| } | ||||
|  | ||||
| func (f *gradleExecuteBuildFileMock) FileExists(path string) (bool, error) { | ||||
| 	return strings.EqualFold(path, "path/to/gradle.build"), nil | ||||
| } | ||||
|  | ||||
| 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) { | ||||
| 		options := &gradleExecuteBuildOptions{ | ||||
| 			Path: "path/to/project/build.gradle", | ||||
| 		} | ||||
| 		u := newShellExecuteTestsUtils() | ||||
|  | ||||
| 		m := &gradleExecuteBuildFileMock{} | ||||
|  | ||||
| 		err := runGradleExecuteBuild(options, nil, u, m) | ||||
| 		assert.EqualError(t, err, "the specified gradle script could not be found") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("success case - build.gradle is present", func(t *testing.T) { | ||||
| 		o := &gradleExecuteBuildOptions{ | ||||
| 			Path: "path/to/gradle.build", | ||||
| 		} | ||||
|  | ||||
| 		u := newGradleExecuteBuildTestsUtils() | ||||
| 		m := &gradleExecuteBuildFileMock{} | ||||
|  | ||||
| 		err := runGradleExecuteBuild(o, nil, u, m) | ||||
| 		assert.NoError(t, err) | ||||
| 	}) | ||||
|  | ||||
| } | ||||
| @@ -53,6 +53,7 @@ func GetAllStepMetadata() map[string]config.StepData { | ||||
| 		"githubSetCommitStatus":                     githubSetCommitStatusMetadata(), | ||||
| 		"gitopsUpdateDeployment":                    gitopsUpdateDeploymentMetadata(), | ||||
| 		"golangBuild":                               golangBuildMetadata(), | ||||
| 		"gradleExecuteBuild":                        gradleExecuteBuildMetadata(), | ||||
| 		"hadolintExecute":                           hadolintExecuteMetadata(), | ||||
| 		"influxWriteData":                           influxWriteDataMetadata(), | ||||
| 		"integrationArtifactDeploy":                 integrationArtifactDeployMetadata(), | ||||
|   | ||||
| @@ -175,6 +175,7 @@ func Execute() { | ||||
| 	rootCmd.AddCommand(ShellExecuteCommand()) | ||||
| 	rootCmd.AddCommand(ApiProxyDownloadCommand()) | ||||
| 	rootCmd.AddCommand(ApiKeyValueMapDownloadCommand()) | ||||
| 	rootCmd.AddCommand(GradleExecuteBuildCommand()) | ||||
|  | ||||
| 	addRootFlags(rootCmd) | ||||
|  | ||||
|   | ||||
							
								
								
									
										7
									
								
								documentation/docs/steps/gradleExecuteBuild.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								documentation/docs/steps/gradleExecuteBuild.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| # ${docGenStepName} | ||||
|  | ||||
| ## ${docGenDescription} | ||||
|  | ||||
| ## ${docGenParameters} | ||||
|  | ||||
| ## ${docGenConfiguration} | ||||
| @@ -103,6 +103,7 @@ nav: | ||||
|         - githubPublishRelease: steps/githubPublishRelease.md | ||||
|         - githubSetCommitStatus: steps/githubSetCommitStatus.md | ||||
|         - gitopsUpdateDeployment: steps/gitopsUpdateDeployment.md | ||||
|         - gradleExecuteBuild: steps/gradleExecuteBuild.md | ||||
|         - hadolintExecute: steps/hadolintExecute.md | ||||
|         - handlePipelineStepErrors: steps/handlePipelineStepErrors.md | ||||
|         - healthExecuteCheck: steps/healthExecuteCheck.md | ||||
|   | ||||
							
								
								
									
										76
									
								
								pkg/gradle/gradle.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								pkg/gradle/gradle.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | ||||
| package gradle | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
|  | ||||
| 	"github.com/SAP/jenkins-library/pkg/log" | ||||
| 	"github.com/SAP/jenkins-library/pkg/piperutils" | ||||
| ) | ||||
|  | ||||
| const exec = "gradle" | ||||
|  | ||||
| type Utils interface { | ||||
| 	Stdout(out io.Writer) | ||||
| 	Stderr(err io.Writer) | ||||
| 	RunExecutable(e string, p ...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"` | ||||
| 	ReturnStdout    bool   `json:"returnStdout,omitempty"` | ||||
| } | ||||
|  | ||||
| func Execute(options *ExecuteOptions, utils Utils, fileUtils piperutils.FileUtils) (string, error) { | ||||
|  | ||||
| 	exists, err := fileUtils.FileExists(options.BuildGradlePath) | ||||
| 	if !exists { | ||||
| 		return "", fmt.Errorf("the specified gradle script could not be found") | ||||
| 	} | ||||
|  | ||||
| 	stdOutBuf, stdOut := evaluateStdOut(options) | ||||
| 	utils.Stdout(stdOut) | ||||
| 	utils.Stderr(log.Writer()) | ||||
|  | ||||
| 	parameters := getParametersFromOptions(options) | ||||
|  | ||||
| 	err = utils.RunExecutable(exec, parameters...) | ||||
| 	if err != nil { | ||||
| 		log.SetErrorCategory(log.ErrorBuild) | ||||
| 		commandLine := append([]string{exec}, parameters...) | ||||
| 		return "", fmt.Errorf("failed to run executable, command: '%s', error: %w", commandLine, err) | ||||
| 	} | ||||
|  | ||||
| 	if stdOutBuf == nil { | ||||
| 		return "", nil | ||||
| 	} | ||||
| 	return string(stdOutBuf.Bytes()), nil | ||||
| } | ||||
|  | ||||
| func evaluateStdOut(options *ExecuteOptions) (*bytes.Buffer, io.Writer) { | ||||
| 	var stdOutBuf *bytes.Buffer | ||||
| 	stdOut := log.Writer() | ||||
| 	if options.ReturnStdout { | ||||
| 		stdOutBuf = new(bytes.Buffer) | ||||
| 		stdOut = io.MultiWriter(stdOut, stdOutBuf) | ||||
| 	} | ||||
| 	return stdOutBuf, stdOut | ||||
| } | ||||
|  | ||||
| func getParametersFromOptions(options *ExecuteOptions) []string { | ||||
| 	var parameters []string | ||||
|  | ||||
| 	// default value for task is 'build', so no necessary to checking for empty parameter | ||||
| 	parameters = append(parameters, options.Task) | ||||
|  | ||||
| 	// resolve path for build.gradle execution | ||||
| 	if options.BuildGradlePath != "" { | ||||
| 		parameters = append(parameters, "-p") | ||||
| 		parameters = append(parameters, options.BuildGradlePath) | ||||
| 	} | ||||
|  | ||||
| 	return parameters | ||||
| } | ||||
							
								
								
									
										29
									
								
								resources/metadata/gradleExecuteBuild.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								resources/metadata/gradleExecuteBuild.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| metadata: | ||||
|   name: gradleExecuteBuild | ||||
|   description: This step runs a gradle build command with parameters provided to the step. | ||||
|   longDescription: This step runs a gradle build command with parameters provided to the step. | ||||
| spec: | ||||
|   inputs: | ||||
|     params: | ||||
|       - name: path | ||||
|         aliases: | ||||
|           - name: buildGradlePath | ||||
|             deprecated: false | ||||
|         type: string | ||||
|         description: Path to the folder with gradle.build file which should be executed. | ||||
|         scope: | ||||
|           - PARAMETERS | ||||
|           - STEPS | ||||
|         mandatory: false | ||||
|       - name: task | ||||
|         type: string | ||||
|         description: Gradle task that should be executed. | ||||
|         scope: | ||||
|           - PARAMETERS | ||||
|           - STAGES | ||||
|           - STEPS | ||||
|         mandatory: false | ||||
|         default: build | ||||
|   containers: | ||||
|     - name: gradle | ||||
|       image: gradle:4.7.0-jdk8-alpine | ||||
| @@ -205,6 +205,7 @@ public class CommonStepsTest extends BasePiperTest{ | ||||
|         'golangBuild', //implementing new golang pattern without fields | ||||
|         'apiProxyDownload', //implementing new golang pattern without fields | ||||
|         'apiKeyValueMapDownload', //implementing new golang pattern without fields | ||||
|         'gradleExecuteBuild', //implementing new golang pattern without fields | ||||
|         'shellExecute', //implementing new golang pattern without fields | ||||
|     ] | ||||
|  | ||||
|   | ||||
							
								
								
									
										9
									
								
								vars/gradleExecuteBuild.groovy
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								vars/gradleExecuteBuild.groovy
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| import groovy.transform.Field | ||||
|  | ||||
| @Field String STEP_NAME = getClass().getName() | ||||
| @Field String METADATA_FILE = 'metadata/gradleExecuteBuild.yaml' | ||||
|  | ||||
| void call(Map parameters = [:]) { | ||||
|     List credentials = [] | ||||
|     piperExecuteBin(parameters, STEP_NAME, METADATA_FILE, credentials) | ||||
| } | ||||
		Reference in New Issue
	
	Block a user