1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2025-09-16 09:26:22 +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:
Eugene Kortelyov
2021-12-22 17:34:36 +03:00
committed by GitHub
parent 5372074d7f
commit 4d787ded6d
12 changed files with 407 additions and 0 deletions

50
cmd/gradleExecuteBuild.go Normal file
View 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
}

View 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
}

View 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")
}

View 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)
})
}

View File

@@ -53,6 +53,7 @@ func GetAllStepMetadata() map[string]config.StepData {
"githubSetCommitStatus": githubSetCommitStatusMetadata(),
"gitopsUpdateDeployment": gitopsUpdateDeploymentMetadata(),
"golangBuild": golangBuildMetadata(),
"gradleExecuteBuild": gradleExecuteBuildMetadata(),
"hadolintExecute": hadolintExecuteMetadata(),
"influxWriteData": influxWriteDataMetadata(),
"integrationArtifactDeploy": integrationArtifactDeployMetadata(),

View File

@@ -175,6 +175,7 @@ func Execute() {
rootCmd.AddCommand(ShellExecuteCommand())
rootCmd.AddCommand(ApiProxyDownloadCommand())
rootCmd.AddCommand(ApiKeyValueMapDownloadCommand())
rootCmd.AddCommand(GradleExecuteBuildCommand())
addRootFlags(rootCmd)

View File

@@ -0,0 +1,7 @@
# ${docGenStepName}
## ${docGenDescription}
## ${docGenParameters}
## ${docGenConfiguration}

View File

@@ -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
View 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
}

View 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

View File

@@ -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
]

View 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)
}