mirror of
https://github.com/SAP/jenkins-library.git
synced 2025-01-20 05:19:40 +02:00
New step mavenExecuteIntegration (#1829)
Co-authored-by: Florian Wilhelm <florian.wilhelm02@sap.com>
This commit is contained in:
parent
77028bf50c
commit
a61798ccbf
106
cmd/mavenExecuteIntegration.go
Normal file
106
cmd/mavenExecuteIntegration.go
Normal file
@ -0,0 +1,106 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/SAP/jenkins-library/pkg/command"
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
"github.com/SAP/jenkins-library/pkg/maven"
|
||||
"github.com/SAP/jenkins-library/pkg/piperutils"
|
||||
"github.com/SAP/jenkins-library/pkg/telemetry"
|
||||
"io"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
type mavenExecuteIntegrationUtils interface {
|
||||
Stdout(out io.Writer)
|
||||
Stderr(err io.Writer)
|
||||
RunExecutable(e string, p ...string) error
|
||||
|
||||
FileExists(filename string) (bool, error)
|
||||
}
|
||||
|
||||
type mavenExecuteIntegrationUtilsBundle struct {
|
||||
*command.Command
|
||||
*piperutils.Files
|
||||
}
|
||||
|
||||
func newMavenExecuteIntegrationUtils() mavenExecuteIntegrationUtils {
|
||||
utils := mavenExecuteIntegrationUtilsBundle{
|
||||
Command: &command.Command{},
|
||||
Files: &piperutils.Files{},
|
||||
}
|
||||
utils.Stdout(log.Writer())
|
||||
utils.Stderr(log.Writer())
|
||||
return &utils
|
||||
}
|
||||
|
||||
func mavenExecuteIntegration(config mavenExecuteIntegrationOptions, _ *telemetry.CustomData) {
|
||||
utils := newMavenExecuteIntegrationUtils()
|
||||
err := runMavenExecuteIntegration(&config, utils)
|
||||
if err != nil {
|
||||
log.Entry().WithError(err).Fatal("step execution failed")
|
||||
}
|
||||
}
|
||||
|
||||
func runMavenExecuteIntegration(config *mavenExecuteIntegrationOptions, utils mavenExecuteIntegrationUtils) error {
|
||||
pomPath := filepath.Join("integration-tests", "pom.xml")
|
||||
hasIntegrationTestsModule, _ := utils.FileExists(pomPath)
|
||||
if !hasIntegrationTestsModule {
|
||||
return fmt.Errorf("maven module 'integration-tests' does not exist in project structure")
|
||||
}
|
||||
|
||||
if err := validateForkCount(config.ForkCount); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
retryDefine := fmt.Sprintf("-Dsurefire.rerunFailingTestsCount=%v", config.Retry)
|
||||
forkCountDefine := fmt.Sprintf("-Dsurefire.forkCount=%v", config.ForkCount)
|
||||
|
||||
mavenOptions := maven.ExecuteOptions{
|
||||
PomPath: pomPath,
|
||||
M2Path: config.M2Path,
|
||||
ProjectSettingsFile: config.ProjectSettingsFile,
|
||||
GlobalSettingsFile: config.GlobalSettingsFile,
|
||||
Goals: []string{"org.jacoco:jacoco-maven-plugin:prepare-agent", "test"},
|
||||
Defines: []string{retryDefine, forkCountDefine},
|
||||
}
|
||||
|
||||
_, err := maven.Execute(&mavenOptions, utils)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func validateForkCount(value string) error {
|
||||
var err error
|
||||
|
||||
if strings.HasSuffix(value, "C") {
|
||||
value := strings.TrimSuffix(value, "C")
|
||||
for _, c := range value {
|
||||
if !unicode.IsDigit(c) && c != '.' {
|
||||
err = fmt.Errorf("only integers or floats allowed with 'C' suffix")
|
||||
break
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
_, err = strconv.ParseFloat(value, 64)
|
||||
}
|
||||
} else {
|
||||
for _, c := range value {
|
||||
if !unicode.IsDigit(c) {
|
||||
err = fmt.Errorf("only integers allowed without 'C' suffix")
|
||||
break
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
_, err = strconv.ParseInt(value, 10, 64)
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid forkCount parameter '%v': %w, please see https://maven.apache.org/surefire/maven-surefire-plugin/test-mojo.html#forkCount for details", value, err)
|
||||
}
|
||||
return nil
|
||||
}
|
153
cmd/mavenExecuteIntegration_generated.go
Normal file
153
cmd/mavenExecuteIntegration_generated.go
Normal file
@ -0,0 +1,153 @@
|
||||
// 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/telemetry"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type mavenExecuteIntegrationOptions struct {
|
||||
Retry int `json:"retry,omitempty"`
|
||||
ForkCount string `json:"forkCount,omitempty"`
|
||||
ProjectSettingsFile string `json:"projectSettingsFile,omitempty"`
|
||||
GlobalSettingsFile string `json:"globalSettingsFile,omitempty"`
|
||||
M2Path string `json:"m2Path,omitempty"`
|
||||
LogSuccessfulMavenTransfers bool `json:"logSuccessfulMavenTransfers,omitempty"`
|
||||
}
|
||||
|
||||
// MavenExecuteIntegrationCommand This step will execute backend integration tests via the Jacoco Maven-plugin.
|
||||
func MavenExecuteIntegrationCommand() *cobra.Command {
|
||||
const STEP_NAME = "mavenExecuteIntegration"
|
||||
|
||||
metadata := mavenExecuteIntegrationMetadata()
|
||||
var stepConfig mavenExecuteIntegrationOptions
|
||||
var startTime time.Time
|
||||
|
||||
var createMavenExecuteIntegrationCmd = &cobra.Command{
|
||||
Use: STEP_NAME,
|
||||
Short: "This step will execute backend integration tests via the Jacoco Maven-plugin.",
|
||||
Long: `If the project contains a Maven module named "integration-tests", this step will execute
|
||||
the integration tests via the Jacoco Maven-plugin.`,
|
||||
PreRunE: func(cmd *cobra.Command, _ []string) error {
|
||||
startTime = time.Now()
|
||||
log.SetStepName(STEP_NAME)
|
||||
log.SetVerbose(GeneralConfig.Verbose)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
Run: func(_ *cobra.Command, _ []string) {
|
||||
telemetryData := telemetry.CustomData{}
|
||||
telemetryData.ErrorCode = "1"
|
||||
handler := func() {
|
||||
telemetryData.Duration = fmt.Sprintf("%v", time.Since(startTime).Milliseconds())
|
||||
telemetry.Send(&telemetryData)
|
||||
}
|
||||
log.DeferExitHandler(handler)
|
||||
defer handler()
|
||||
telemetry.Initialize(GeneralConfig.NoTelemetry, STEP_NAME)
|
||||
mavenExecuteIntegration(stepConfig, &telemetryData)
|
||||
telemetryData.ErrorCode = "0"
|
||||
log.Entry().Info("SUCCESS")
|
||||
},
|
||||
}
|
||||
|
||||
addMavenExecuteIntegrationFlags(createMavenExecuteIntegrationCmd, &stepConfig)
|
||||
return createMavenExecuteIntegrationCmd
|
||||
}
|
||||
|
||||
func addMavenExecuteIntegrationFlags(cmd *cobra.Command, stepConfig *mavenExecuteIntegrationOptions) {
|
||||
cmd.Flags().IntVar(&stepConfig.Retry, "retry", 1, "The number of times that integration tests will be retried before failing the step. Note: This will consume more time for the step execution.")
|
||||
cmd.Flags().StringVar(&stepConfig.ForkCount, "forkCount", `1C`, "The number of JVM processes that are spawned to run the tests in parallel in case of using a maven based project structure. For more details visit the Surefire documentation at https://maven.apache.org/surefire/maven-surefire-plugin/test-mojo.html#forkCount.")
|
||||
cmd.Flags().StringVar(&stepConfig.ProjectSettingsFile, "projectSettingsFile", os.Getenv("PIPER_projectSettingsFile"), "Path to the mvn settings file that should be used as project settings file.")
|
||||
cmd.Flags().StringVar(&stepConfig.GlobalSettingsFile, "globalSettingsFile", os.Getenv("PIPER_globalSettingsFile"), "Path to the mvn settings file that should be used as global settings file.")
|
||||
cmd.Flags().StringVar(&stepConfig.M2Path, "m2Path", os.Getenv("PIPER_m2Path"), "Path to the location of the local repository that should be used.")
|
||||
cmd.Flags().BoolVar(&stepConfig.LogSuccessfulMavenTransfers, "logSuccessfulMavenTransfers", false, "Configures maven to log successful downloads. This is set to `false` by default to reduce the noise in build logs.")
|
||||
|
||||
}
|
||||
|
||||
// retrieve step metadata
|
||||
func mavenExecuteIntegrationMetadata() config.StepData {
|
||||
var theMetaData = config.StepData{
|
||||
Metadata: config.StepMetadata{
|
||||
Name: "mavenExecuteIntegration",
|
||||
Aliases: []config.Alias{{Name: "mavenExecute", Deprecated: false}},
|
||||
},
|
||||
Spec: config.StepSpec{
|
||||
Inputs: config.StepInputs{
|
||||
Parameters: []config.StepParameters{
|
||||
{
|
||||
Name: "retry",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STEPS", "STAGES"},
|
||||
Type: "int",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{},
|
||||
},
|
||||
{
|
||||
Name: "forkCount",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STEPS", "STAGES"},
|
||||
Type: "string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{},
|
||||
},
|
||||
{
|
||||
Name: "projectSettingsFile",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"GENERAL", "STEPS", "STAGES", "PARAMETERS"},
|
||||
Type: "string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{{Name: "maven/projectSettingsFile"}},
|
||||
},
|
||||
{
|
||||
Name: "globalSettingsFile",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"GENERAL", "STEPS", "STAGES", "PARAMETERS"},
|
||||
Type: "string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{{Name: "maven/globalSettingsFile"}},
|
||||
},
|
||||
{
|
||||
Name: "m2Path",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"GENERAL", "STEPS", "STAGES", "PARAMETERS"},
|
||||
Type: "string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{{Name: "maven/m2Path"}},
|
||||
},
|
||||
{
|
||||
Name: "logSuccessfulMavenTransfers",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"GENERAL", "STEPS", "STAGES", "PARAMETERS"},
|
||||
Type: "bool",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{{Name: "maven/logSuccessfulMavenTransfers"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
return theMetaData
|
||||
}
|
16
cmd/mavenExecuteIntegration_generated_test.go
Normal file
16
cmd/mavenExecuteIntegration_generated_test.go
Normal file
@ -0,0 +1,16 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestMavenExecuteIntegrationCommand(t *testing.T) {
|
||||
|
||||
testCmd := MavenExecuteIntegrationCommand()
|
||||
|
||||
// only high level testing performed - details are tested in step generation procudure
|
||||
assert.Equal(t, "mavenExecuteIntegration", testCmd.Use, "command name incorrect")
|
||||
|
||||
}
|
133
cmd/mavenExecuteIntegration_test.go
Normal file
133
cmd/mavenExecuteIntegration_test.go
Normal file
@ -0,0 +1,133 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/SAP/jenkins-library/pkg/mock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type mavenExecuteIntegrationTestUtilsBundle struct {
|
||||
*mock.ExecMockRunner
|
||||
*mock.FilesMock
|
||||
}
|
||||
|
||||
func TestIntegrationTestModuleDoesNotExist(t *testing.T) {
|
||||
utils := newMavenIntegrationTestsUtilsBundle()
|
||||
config := mavenExecuteIntegrationOptions{}
|
||||
|
||||
err := runMavenExecuteIntegration(&config, utils)
|
||||
|
||||
assert.EqualError(t, err, "maven module 'integration-tests' does not exist in project structure")
|
||||
}
|
||||
|
||||
func TestHappyPathIntegrationTests(t *testing.T) {
|
||||
utils := newMavenIntegrationTestsUtilsBundle()
|
||||
utils.FilesMock.AddFile("integration-tests/pom.xml", []byte(`<project> </project>`))
|
||||
|
||||
config := mavenExecuteIntegrationOptions{
|
||||
Retry: 2,
|
||||
ForkCount: "1C",
|
||||
}
|
||||
|
||||
err := runMavenExecuteIntegration(&config, utils)
|
||||
if err != nil {
|
||||
t.Fatalf("Error %s", err)
|
||||
}
|
||||
|
||||
expectedParameters1 := []string{
|
||||
"--file",
|
||||
"integration-tests/pom.xml",
|
||||
"-Dsurefire.rerunFailingTestsCount=2",
|
||||
"-Dsurefire.forkCount=1C",
|
||||
"-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn",
|
||||
"--batch-mode",
|
||||
"org.jacoco:jacoco-maven-plugin:prepare-agent",
|
||||
"test",
|
||||
}
|
||||
|
||||
assert.Equal(t, mock.ExecCall{Exec: "mvn", Params: expectedParameters1}, utils.ExecMockRunner.Calls[0])
|
||||
}
|
||||
|
||||
func TestInvalidForkCountParam(t *testing.T) {
|
||||
// init
|
||||
utils := newMavenIntegrationTestsUtilsBundle()
|
||||
utils.FilesMock.AddFile("integration-tests/pom.xml", []byte(`<project> </project>`))
|
||||
|
||||
// test
|
||||
err := runMavenExecuteIntegration(&mavenExecuteIntegrationOptions{ForkCount: "4.2"}, utils)
|
||||
|
||||
// assert
|
||||
if assert.Error(t, err) {
|
||||
assert.Contains(t, err.Error(), "invalid forkCount parameter")
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateForkCount(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
testValue string
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
name: "valid integer",
|
||||
testValue: "2",
|
||||
expectedError: "",
|
||||
},
|
||||
{
|
||||
name: "zero is valid",
|
||||
testValue: "0",
|
||||
expectedError: "",
|
||||
},
|
||||
{
|
||||
name: "valid floating point",
|
||||
testValue: "2.5C",
|
||||
expectedError: "",
|
||||
},
|
||||
{
|
||||
name: "valid integer with C",
|
||||
testValue: "2C",
|
||||
expectedError: "",
|
||||
},
|
||||
{
|
||||
name: "invalid floating point",
|
||||
testValue: "1.2",
|
||||
expectedError: "invalid forkCount parameter",
|
||||
},
|
||||
{
|
||||
name: "invalid",
|
||||
testValue: "C1",
|
||||
expectedError: "invalid forkCount parameter",
|
||||
},
|
||||
{
|
||||
name: "another invalid",
|
||||
testValue: "1 C",
|
||||
expectedError: "invalid forkCount parameter",
|
||||
},
|
||||
{
|
||||
name: "invalid float",
|
||||
testValue: "1..2C",
|
||||
expectedError: "invalid forkCount parameter",
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
err := validateForkCount(testCase.testValue)
|
||||
if testCase.expectedError == "" {
|
||||
assert.NoError(t, err)
|
||||
} else if assert.Error(t, err) {
|
||||
assert.Contains(t, err.Error(), testCase.expectedError)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func newMavenIntegrationTestsUtilsBundle() mavenExecuteIntegrationTestUtilsBundle {
|
||||
utilsBundle := mavenExecuteIntegrationTestUtilsBundle{
|
||||
ExecMockRunner: &mock.ExecMockRunner{},
|
||||
FilesMock: &mock.FilesMock{},
|
||||
}
|
||||
return utilsBundle
|
||||
}
|
@ -81,6 +81,7 @@ func Execute() {
|
||||
rootCmd.AddCommand(MavenExecuteCommand())
|
||||
rootCmd.AddCommand(CloudFoundryCreateServiceKeyCommand())
|
||||
rootCmd.AddCommand(MavenBuildCommand())
|
||||
rootCmd.AddCommand(MavenExecuteIntegrationCommand())
|
||||
rootCmd.AddCommand(MavenExecuteStaticCodeChecksCommand())
|
||||
rootCmd.AddCommand(NexusUploadCommand())
|
||||
rootCmd.AddCommand(AbapEnvironmentRunATCCheckCommand())
|
||||
|
7
documentation/docs/steps/mavenExecuteIntegration.md
Normal file
7
documentation/docs/steps/mavenExecuteIntegration.md
Normal file
@ -0,0 +1,7 @@
|
||||
# ${docGenStepName}
|
||||
|
||||
## ${docGenDescription}
|
||||
|
||||
## ${docGenParameters}
|
||||
|
||||
## ${docGenConfiguration}
|
@ -24,6 +24,16 @@ func TestMavenBuildCloudSdkSpringProject(t *testing.T) {
|
||||
container.assertHasOutput(t, "BUILD SUCCESS")
|
||||
container.assertHasFile(t, "/project/application/target/cloud-sdk-spring-archetype-application.jar")
|
||||
container.assertHasFile(t, "/tmp/.m2/repository")
|
||||
|
||||
err = container.whenRunningPiperCommand("mavenExecuteIntegration", "")
|
||||
if err != nil {
|
||||
t.Fatalf("Calling piper command filed %s", err)
|
||||
}
|
||||
|
||||
container.assertHasOutput(t, "INFO mydemo.HelloWorldControllerTest - Starting HelloWorldControllerTest")
|
||||
container.assertHasOutput(t, "Tests run: 1, Failures: 0, Errors: 0, Skipped: 0")
|
||||
|
||||
container.assertHasFile(t, "/project/integration-tests/target/coverage-reports/jacoco.exec")
|
||||
}
|
||||
|
||||
func TestMavenBuildCloudSdkTomeeProject(t *testing.T) {
|
||||
@ -44,4 +54,14 @@ func TestMavenBuildCloudSdkTomeeProject(t *testing.T) {
|
||||
container.assertHasFile(t, "/project/application/target/cloud-sdk-tomee-archetype-application-classes.jar")
|
||||
container.assertHasFile(t, "/project/application/target/cloud-sdk-tomee-archetype-application.war")
|
||||
container.assertHasFile(t, "/tmp/.m2/repository")
|
||||
|
||||
err = container.whenRunningPiperCommand("mavenExecuteIntegration", "")
|
||||
if err != nil {
|
||||
t.Fatalf("Calling piper command filed %s", err)
|
||||
}
|
||||
|
||||
container.assertHasOutput(t, "(prepare-agent) @ cloud-sdk-tomee-archetype-integration-tests")
|
||||
container.assertHasOutput(t, "Tests run: 1, Failures: 0, Errors: 0, Skipped: 0")
|
||||
|
||||
container.assertHasFile(t, "/project/integration-tests/target/coverage-reports/jacoco.exec")
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
general:
|
||||
steps:
|
||||
mavenBuild:
|
||||
maven:
|
||||
globalSettingsFile: settings.xml
|
||||
steps:
|
||||
stages:
|
||||
|
@ -1,5 +1,5 @@
|
||||
general:
|
||||
steps:
|
||||
mavenBuild:
|
||||
maven:
|
||||
globalSettingsFile: settings.xml
|
||||
steps:
|
||||
stages:
|
||||
|
85
resources/metadata/mavenExecuteIntegration.yaml
Normal file
85
resources/metadata/mavenExecuteIntegration.yaml
Normal file
@ -0,0 +1,85 @@
|
||||
metadata:
|
||||
name: mavenExecuteIntegration
|
||||
aliases:
|
||||
- name: mavenExecute
|
||||
deprecated: false
|
||||
description: "This step will execute backend integration tests via the Jacoco Maven-plugin."
|
||||
longDescription: |
|
||||
If the project contains a Maven module named "integration-tests", this step will execute
|
||||
the integration tests via the Jacoco Maven-plugin.
|
||||
spec:
|
||||
inputs:
|
||||
params:
|
||||
- name: retry
|
||||
type: int
|
||||
description: "The number of times that integration tests will be retried before failing the step.
|
||||
Note: This will consume more time for the step execution."
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STEPS
|
||||
- STAGES
|
||||
default: 1
|
||||
- name: forkCount
|
||||
type: string
|
||||
description: "The number of JVM processes that are spawned to run the tests in parallel in case of
|
||||
using a maven based project structure.
|
||||
For more details visit the Surefire documentation at
|
||||
https://maven.apache.org/surefire/maven-surefire-plugin/test-mojo.html#forkCount."
|
||||
scope:
|
||||
- PARAMETERS
|
||||
- STEPS
|
||||
- STAGES
|
||||
default: "1C"
|
||||
|
||||
# Global maven settings, should be added to all maven steps
|
||||
- name: projectSettingsFile
|
||||
type: string
|
||||
description: "Path to the mvn settings file that should be used as project settings file."
|
||||
scope:
|
||||
- GENERAL
|
||||
- STEPS
|
||||
- STAGES
|
||||
- PARAMETERS
|
||||
aliases:
|
||||
- name: maven/projectSettingsFile
|
||||
- name: globalSettingsFile
|
||||
type: string
|
||||
description: "Path to the mvn settings file that should be used as global settings file."
|
||||
scope:
|
||||
- GENERAL
|
||||
- STEPS
|
||||
- STAGES
|
||||
- PARAMETERS
|
||||
aliases:
|
||||
- name: maven/globalSettingsFile
|
||||
- name: m2Path
|
||||
type: string
|
||||
description: "Path to the location of the local repository that should be used."
|
||||
scope:
|
||||
- GENERAL
|
||||
- STEPS
|
||||
- STAGES
|
||||
- PARAMETERS
|
||||
aliases:
|
||||
- name: maven/m2Path
|
||||
- name: logSuccessfulMavenTransfers
|
||||
type: bool
|
||||
description: "Configures maven to log successful downloads.
|
||||
This is set to `false` by default to reduce the noise in build logs."
|
||||
scope:
|
||||
- GENERAL
|
||||
- STEPS
|
||||
- STAGES
|
||||
- PARAMETERS
|
||||
default: false
|
||||
aliases:
|
||||
- name: maven/logSuccessfulMavenTransfers
|
||||
|
||||
containers:
|
||||
- name: mvn
|
||||
image: maven:3.6-jdk-8
|
||||
imagePullPolicy: Never
|
||||
|
||||
# This declaration is necessary in order to return any sidecar configuration in the context config.
|
||||
sidecars:
|
||||
- name: ''
|
@ -4,31 +4,33 @@ package com.sap.piper
|
||||
class DownloadCacheUtils {
|
||||
|
||||
static Map injectDownloadCacheInParameters(Script script, Map parameters, BuildTool buildTool) {
|
||||
if (DownloadCacheUtils.isEnabled(script)) {
|
||||
if (!isEnabled(script)) {
|
||||
return parameters
|
||||
}
|
||||
|
||||
if (!parameters.dockerOptions) {
|
||||
parameters.dockerOptions = []
|
||||
}
|
||||
if (parameters.dockerOptions instanceof CharSequence) {
|
||||
parameters.dockerOptions = [parameters.dockerOptions]
|
||||
if (!parameters.dockerOptions) {
|
||||
parameters.dockerOptions = []
|
||||
}
|
||||
if (parameters.dockerOptions instanceof CharSequence) {
|
||||
parameters.dockerOptions = [parameters.dockerOptions]
|
||||
}
|
||||
|
||||
if (!(parameters.dockerOptions instanceof List)) {
|
||||
throw new IllegalArgumentException("Unexpected type for dockerOptions. Expected was either a list or a string. Actual type was: '${parameters.dockerOptions.getClass()}'")
|
||||
}
|
||||
parameters.dockerOptions.add(getDockerOptions(script))
|
||||
|
||||
if (buildTool == BuildTool.MAVEN || buildTool == BuildTool.MTA) {
|
||||
String globalSettingsFile = getGlobalMavenSettingsForDownloadCache(script)
|
||||
if (parameters.globalSettingsFile && parameters.globalSettingsFile != globalSettingsFile) {
|
||||
throw new IllegalArgumentException("You can not specify the parameter globalSettingsFile if the download cache is active")
|
||||
}
|
||||
|
||||
if (!(parameters.dockerOptions instanceof List)) {
|
||||
throw new IllegalArgumentException("Unexpected type for dockerOptions. Expected was either a list or a string. Actual type was: '${parameters.dockerOptions.getClass()}'")
|
||||
}
|
||||
parameters.dockerOptions.add(DownloadCacheUtils.getDockerOptions(script))
|
||||
parameters.globalSettingsFile = globalSettingsFile
|
||||
}
|
||||
|
||||
if (buildTool == BuildTool.MAVEN || buildTool == BuildTool.MTA) {
|
||||
if (parameters.globalSettingsFile) {
|
||||
throw new IllegalArgumentException("You can not specify the parameter globalSettingsFile if the download cache is active")
|
||||
}
|
||||
|
||||
parameters.globalSettingsFile = DownloadCacheUtils.getGlobalMavenSettingsForDownloadCache(script)
|
||||
}
|
||||
|
||||
if (buildTool == BuildTool.NPM || buildTool == buildTool.MTA) {
|
||||
parameters['defaultNpmRegistry'] = DownloadCacheUtils.getNpmRegistryUri(script)
|
||||
}
|
||||
if (buildTool == BuildTool.NPM || buildTool == BuildTool.MTA) {
|
||||
parameters['defaultNpmRegistry'] = getNpmRegistryUri(script)
|
||||
}
|
||||
|
||||
return parameters
|
||||
@ -47,6 +49,15 @@ class DownloadCacheUtils {
|
||||
return false
|
||||
}
|
||||
|
||||
// Do not enable the DL-cache when a sidecar image is specified.
|
||||
// This is necessary because it is currently not possible to connect a container to multiple networks.
|
||||
// Can be removed when docker plugin supports multiple networks and jenkins-library implemented that feature
|
||||
// See also https://github.com/SAP/jenkins-library/issues/1864
|
||||
if (script.env.SIDECAR_IMAGE) {
|
||||
script.echo "Download cache disabled while running with sidecar image (${script.env.SIDECAR_IMAGE})"
|
||||
return false
|
||||
}
|
||||
|
||||
return (networkName() && hostname())
|
||||
}
|
||||
|
||||
|
@ -134,6 +134,7 @@ public class CommonStepsTest extends BasePiperTest{
|
||||
'malwareExecuteScan', //implementing new golang pattern without fields
|
||||
'mavenBuild', //implementing new golang pattern without fields
|
||||
'mavenExecute', //implementing new golang pattern without fields
|
||||
'mavenExecuteIntegration', //implementing new golang pattern without fields
|
||||
'mavenExecuteStaticCodeChecks', //implementing new golang pattern without fields
|
||||
'mtaBuild', //implementing new golang pattern without fields
|
||||
'nexusUpload', //implementing new golang pattern without fields
|
||||
|
72
test/groovy/MavenExecuteIntegrationTest.groovy
Normal file
72
test/groovy/MavenExecuteIntegrationTest.groovy
Normal file
@ -0,0 +1,72 @@
|
||||
import groovy.json.JsonSlurper
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.ExpectedException
|
||||
import org.junit.rules.RuleChain
|
||||
import util.*
|
||||
|
||||
import static org.hamcrest.Matchers.*
|
||||
import static org.junit.Assert.assertThat
|
||||
|
||||
class MavenExecuteIntegrationTest extends BasePiperTest {
|
||||
private ExpectedException exception = ExpectedException.none()
|
||||
|
||||
private JenkinsCredentialsRule credentialsRule = new JenkinsCredentialsRule(this)
|
||||
private JenkinsShellCallRule shellCallRule = new JenkinsShellCallRule(this)
|
||||
private JenkinsStepRule stepRule = new JenkinsStepRule(this)
|
||||
private JenkinsWriteFileRule writeFileRule = new JenkinsWriteFileRule(this)
|
||||
|
||||
private List withEnvArgs = []
|
||||
|
||||
@Rule
|
||||
public RuleChain rules = Rules
|
||||
.getCommonRules(this)
|
||||
.around(exception)
|
||||
.around(new JenkinsReadYamlRule(this))
|
||||
.around(credentialsRule)
|
||||
.around(new JenkinsReadJsonRule(this))
|
||||
.around(shellCallRule)
|
||||
.around(stepRule)
|
||||
.around(writeFileRule)
|
||||
.around(new JenkinsFileExistsRule(this, []))
|
||||
|
||||
@Before
|
||||
void init() {
|
||||
helper.registerAllowedMethod("readJSON", [Map], { m ->
|
||||
if (m.text instanceof String)
|
||||
return new JsonSlurper().parseText(m.text as String)
|
||||
})
|
||||
helper.registerAllowedMethod("withEnv", [List, Closure], { arguments, closure ->
|
||||
arguments.each {arg ->
|
||||
withEnvArgs.add(arg.toString())
|
||||
}
|
||||
return closure()
|
||||
})
|
||||
shellCallRule.setReturnValue(
|
||||
'./piper getConfig --contextConfig --stepMetadata \'.pipeline/tmp/metadata/mavenExecuteIntegration.yaml\'',
|
||||
'{"verbose": false}'
|
||||
)
|
||||
|
||||
helper.registerAllowedMethod('fileExists', [String], {return true})
|
||||
helper.registerAllowedMethod('findFiles', [Map], {return null})
|
||||
helper.registerAllowedMethod('testsPublishResults', [Map], {return null})
|
||||
}
|
||||
|
||||
@Test
|
||||
void testWithSidecar() {
|
||||
stepRule.step.mavenExecuteIntegration(
|
||||
juStabUtils: utils,
|
||||
jenkinsUtilsStub: jenkinsUtils,
|
||||
testParam: 'This is test content',
|
||||
sidecarImage: 'some/image',
|
||||
script: nullScript,
|
||||
)
|
||||
// asserts
|
||||
assertThat(writeFileRule.files['.pipeline/tmp/metadata/mavenExecuteIntegration.yaml'] as String,
|
||||
containsString('name: mavenExecuteIntegration'))
|
||||
assertThat(withEnvArgs[0], allOf(startsWith('PIPER_parametersJSON'),
|
||||
containsString('"testParam":"This is test content"')))
|
||||
assertThat(shellCallRule.shell[1] as String, is('./piper mavenExecuteIntegration'))
|
||||
}
|
||||
}
|
@ -316,6 +316,14 @@ boolean isContainerDefined(config) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (env.SIDECAR_IMAGE != config.sidecarImage) {
|
||||
// If a sidecar image has been configured for the current stage,
|
||||
// then piperStageWrapper will have set the env.SIDECAR_IMAGE variable.
|
||||
// If the current step overrides the stage's sidecar image,
|
||||
// then a new Pod needs to be spawned.
|
||||
return false
|
||||
}
|
||||
|
||||
return containerMap.get(env.POD_NAME).containsKey(config.dockerImage)
|
||||
}
|
||||
|
||||
|
31
vars/mavenExecuteIntegration.groovy
Normal file
31
vars/mavenExecuteIntegration.groovy
Normal file
@ -0,0 +1,31 @@
|
||||
import com.sap.piper.BuildTool
|
||||
import com.sap.piper.DownloadCacheUtils
|
||||
import groovy.transform.Field
|
||||
|
||||
import static com.sap.piper.Prerequisites.checkScript
|
||||
|
||||
@Field String STEP_NAME = getClass().getName()
|
||||
@Field String METADATA_FILE = 'metadata/mavenExecuteIntegration.yaml'
|
||||
|
||||
@Field Set GENERAL_CONFIG_KEYS = []
|
||||
@Field Set STEP_CONFIG_KEYS = GENERAL_CONFIG_KEYS
|
||||
@Field Set PARAMETER_KEYS = STEP_CONFIG_KEYS.plus([
|
||||
/**
|
||||
* Specify a glob pattern where test result files will be located.
|
||||
*/
|
||||
'reportLocationPattern',
|
||||
])
|
||||
|
||||
//Metadata maintained in file project://resources/metadata/mavenExecuteIntegration.yaml
|
||||
|
||||
void call(Map parameters = [:]) {
|
||||
final script = checkScript(this, parameters) ?: this
|
||||
parameters = DownloadCacheUtils.injectDownloadCacheInParameters(script, parameters, BuildTool.MAVEN)
|
||||
|
||||
try {
|
||||
List credentials = []
|
||||
piperExecuteBin(parameters, STEP_NAME, METADATA_FILE, credentials)
|
||||
} finally {
|
||||
testsPublishResults(script: script, junit: [allowEmptyResults: true, pattern: parameters.reportLocationPattern])
|
||||
}
|
||||
}
|
@ -48,7 +48,7 @@ void call(Map parameters = [:], String stepName, String metadataFile, List crede
|
||||
}
|
||||
|
||||
// prepare stashes
|
||||
// first eliminate empty stahes
|
||||
// first eliminate empty stashes
|
||||
config.stashContent = utils.unstashAll(config.stashContent)
|
||||
// then make sure that commonPipelineEnvironment, config, ... is also available when step stashing is active
|
||||
if (config.stashContent?.size() > 0) {
|
||||
|
@ -31,20 +31,38 @@ void call(Map parameters = [:], body) {
|
||||
|
||||
stageLocking(config) {
|
||||
def containerMap = ContainerMap.instance.getMap().get(stageName) ?: [:]
|
||||
List environment = []
|
||||
if (config.sidecarImage) {
|
||||
echo "sidecarImage configured for stage '${stageName}': '${config.sidecarImage}'"
|
||||
environment.add("SIDECAR_IMAGE=${config.sidecarImage}")
|
||||
}
|
||||
if (Boolean.valueOf(env.ON_K8S) && (containerMap.size() > 0 || config.runStageInPod)) {
|
||||
withEnv(["POD_NAME=${stageName}"]) {
|
||||
environment.add("POD_NAME=${stageName}")
|
||||
withEnv(environment) {
|
||||
dockerExecuteOnKubernetes(script: script, containerMap: containerMap, stageName: stageName) {
|
||||
executeStage(script, body, stageName, config, utils, parameters.telemetryDisabled)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
node(config.nodeLabel) {
|
||||
executeStage(script, body, stageName, config, utils, parameters.telemetryDisabled)
|
||||
withEnvWrapper(environment) {
|
||||
node(config.nodeLabel) {
|
||||
executeStage(script, body, stageName, config, utils, parameters.telemetryDisabled)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void withEnvWrapper(List environment, Closure body) {
|
||||
if (environment) {
|
||||
withEnv(environment) {
|
||||
body()
|
||||
}
|
||||
} else {
|
||||
body()
|
||||
}
|
||||
}
|
||||
|
||||
private void stageLocking(Map config, Closure body) {
|
||||
if (config.stageLocking) {
|
||||
String resource = config.lockingResourceGroup?:env.JOB_NAME
|
||||
|
Loading…
x
Reference in New Issue
Block a user