You've already forked sap-jenkins-library
mirror of
https://github.com/SAP/jenkins-library.git
synced 2025-11-06 09:09:19 +02:00
Extending mavenBuild step with an option to perform maven deploy with publish flag (#2833)
* modifying detect.maven.excluded.scopes from TEST to test * new maven alt deployment flags * changing flag names * tlsCertificate addtion * adding publish flags * new flags * publish flag * enhance maven builds * enhance maven builds * creating new settings xml * updating project settings * changing interface for artifactPreparation that uses the same maven util niterface * adding general scope to maven params * global reference * removing vault tmp * debuging deployment user * more debug * maven build paras * using smaller case * adding incorrect error check * adding deployment flags * code refactor * unit tests * changing scope of paramter for tls certs * new scope for tls * remove trailing space in mavenBuild.yaml * trailing space fix * typo fix and jenkins secret * including jenkins credentials for repo pass in the maven build groovy Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>
This commit is contained in:
@@ -59,6 +59,8 @@ type artifactPrepareVersionUtils interface {
|
||||
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)
|
||||
}
|
||||
|
||||
type artifactPrepareVersionUtilsBundle struct {
|
||||
|
||||
@@ -1,9 +1,19 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
|
||||
"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"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
piperhttp "github.com/SAP/jenkins-library/pkg/http"
|
||||
)
|
||||
|
||||
func mavenBuild(config mavenBuildOptions, telemetryData *telemetry.CustomData) {
|
||||
@@ -16,6 +26,8 @@ func mavenBuild(config mavenBuildOptions, telemetryData *telemetry.CustomData) {
|
||||
}
|
||||
|
||||
func runMavenBuild(config *mavenBuildOptions, telemetryData *telemetry.CustomData, utils maven.Utils) error {
|
||||
downloadClient := &piperhttp.Client{}
|
||||
|
||||
var flags = []string{"-update-snapshots", "--batch-mode"}
|
||||
|
||||
exists, _ := utils.FileExists("integration-tests/pom.xml")
|
||||
@@ -67,5 +79,123 @@ func runMavenBuild(config *mavenBuildOptions, telemetryData *telemetry.CustomDat
|
||||
}
|
||||
|
||||
_, err := maven.Execute(&mavenOptions, utils)
|
||||
|
||||
if err == nil {
|
||||
if config.Publish && !config.Verify {
|
||||
log.Entry().Infof("publish detected, running mvn deploy")
|
||||
|
||||
runner := &command.Command{}
|
||||
fileUtils := &piperutils.Files{}
|
||||
|
||||
if (len(config.AltDeploymentRepositoryID) > 0) && (len(config.AltDeploymentRepositoryPassword) > 0) && (len(config.AltDeploymentRepositoryUser) > 0) {
|
||||
projectSettingsFilePath, err := createOrUpdateProjectSettingsXML(config.ProjectSettingsFile, config.AltDeploymentRepositoryID, config.AltDeploymentRepositoryUser, config.AltDeploymentRepositoryPassword, utils)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Could not create or update project settings xml")
|
||||
}
|
||||
mavenOptions.ProjectSettingsFile = projectSettingsFilePath
|
||||
}
|
||||
|
||||
deployFlags := []string{"-Dmaven.main.skip=true", "-Dmaven.test.skip=true", "-Dmaven.install.skip=true"}
|
||||
if (len(config.AltDeploymentRepositoryID) > 0) && (len(config.AltDeploymentRepositoryURL) > 0) {
|
||||
deployFlags = append(deployFlags, "-DaltDeploymentRepository="+config.AltDeploymentRepositoryID+"::default::"+config.AltDeploymentRepositoryURL)
|
||||
}
|
||||
|
||||
if err := loadRemoteRepoCertificates(config.CustomTLSCertificateLinks, downloadClient, &deployFlags, runner, fileUtils); err != nil {
|
||||
log.SetErrorCategory(log.ErrorInfrastructure)
|
||||
return err
|
||||
}
|
||||
mavenOptions.Flags = deployFlags
|
||||
mavenOptions.Goals = []string{"deploy"}
|
||||
mavenOptions.Defines = []string{}
|
||||
_, err := maven.Execute(&mavenOptions, utils)
|
||||
return err
|
||||
} else {
|
||||
log.Entry().Infof("publish not detected, ignoring maven deploy")
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func createOrUpdateProjectSettingsXML(projectSettingsFile string, altDeploymentRepositoryID string, altDeploymentRepositoryUser string, altDeploymentRepositoryPassword string, utils maven.Utils) (string, error) {
|
||||
if len(projectSettingsFile) > 0 {
|
||||
projectSettingsFilePath, err := maven.UpdateProjectSettingsXML(projectSettingsFile, altDeploymentRepositoryID, altDeploymentRepositoryUser, altDeploymentRepositoryPassword, utils)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "Could not update settings xml")
|
||||
}
|
||||
return projectSettingsFilePath, nil
|
||||
} else {
|
||||
projectSettingsFilePath, err := maven.CreateNewProjectSettingsXML(altDeploymentRepositoryID, altDeploymentRepositoryUser, altDeploymentRepositoryPassword, utils)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "Could not create settings xml")
|
||||
}
|
||||
return projectSettingsFilePath, nil
|
||||
}
|
||||
}
|
||||
|
||||
func loadRemoteRepoCertificates(certificateList []string, client piperhttp.Downloader, flags *[]string, runner command.ExecRunner, fileUtils piperutils.FileUtils) error {
|
||||
trustStore := filepath.Join(getWorkingDirForTrustStore(), ".pipeline", "keystore.jks")
|
||||
log.Entry().Infof("using trust store %s", trustStore)
|
||||
|
||||
if exists, _ := fileUtils.FileExists(trustStore); exists {
|
||||
maven_opts := "-Djavax.net.ssl.trustStore=" + trustStore + " -Djavax.net.ssl.trustStorePassword=changeit"
|
||||
err := os.Setenv("MAVEN_OPTS", maven_opts)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Could not create MAVEN_OPTS environment variable ")
|
||||
}
|
||||
log.Entry().WithField("trust store", trustStore).Info("Using local trust store")
|
||||
}
|
||||
|
||||
if len(certificateList) > 0 {
|
||||
keytoolOptions := []string{
|
||||
"-import",
|
||||
"-noprompt",
|
||||
"-storepass", "changeit",
|
||||
"-keystore", trustStore,
|
||||
}
|
||||
tmpFolder := getTempDirForCertFile()
|
||||
defer os.RemoveAll(tmpFolder) // clean up
|
||||
|
||||
for _, certificate := range certificateList {
|
||||
filename := path.Base(certificate) // decode?
|
||||
target := filepath.Join(tmpFolder, filename)
|
||||
|
||||
log.Entry().WithField("source", certificate).WithField("target", target).Info("Downloading TLS certificate")
|
||||
// download certificate
|
||||
if err := client.DownloadFile(certificate, target, nil, nil); err != nil {
|
||||
return errors.Wrapf(err, "Download of TLS certificate failed")
|
||||
}
|
||||
options := append(keytoolOptions, "-file", target)
|
||||
options = append(options, "-alias", filename)
|
||||
// add certificate to keystore
|
||||
if err := runner.RunExecutable("keytool", options...); err != nil {
|
||||
return errors.Wrap(err, "Adding certificate to keystore failed")
|
||||
}
|
||||
}
|
||||
|
||||
maven_opts := "-Djavax.net.ssl.trustStore=.pipeline/keystore.jks -Djavax.net.ssl.trustStorePassword=changeit"
|
||||
err := os.Setenv("MAVEN_OPTS", maven_opts)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Could not create MAVEN_OPTS environment variable ")
|
||||
}
|
||||
log.Entry().WithField("trust store", trustStore).Info("Using local trust store")
|
||||
} else {
|
||||
log.Entry().Debug("Download of TLS certificates skipped")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getWorkingDirForTrustStore() string {
|
||||
workingDir, err := os.Getwd()
|
||||
if err != nil {
|
||||
log.Entry().WithError(err).WithField("path", workingDir).Debug("Retrieving of work directory failed")
|
||||
}
|
||||
return workingDir
|
||||
}
|
||||
|
||||
func getTempDirForCertFile() string {
|
||||
tmpFolder, err := ioutil.TempDir(".", "temp-")
|
||||
if err != nil {
|
||||
log.Entry().WithError(err).WithField("path", tmpFolder).Debug("Creating temp directory failed")
|
||||
}
|
||||
return tmpFolder
|
||||
}
|
||||
|
||||
@@ -15,14 +15,20 @@ import (
|
||||
)
|
||||
|
||||
type mavenBuildOptions struct {
|
||||
PomPath string `json:"pomPath,omitempty"`
|
||||
Flatten bool `json:"flatten,omitempty"`
|
||||
Verify bool `json:"verify,omitempty"`
|
||||
ProjectSettingsFile string `json:"projectSettingsFile,omitempty"`
|
||||
GlobalSettingsFile string `json:"globalSettingsFile,omitempty"`
|
||||
M2Path string `json:"m2Path,omitempty"`
|
||||
LogSuccessfulMavenTransfers bool `json:"logSuccessfulMavenTransfers,omitempty"`
|
||||
CreateBOM bool `json:"createBOM,omitempty"`
|
||||
PomPath string `json:"pomPath,omitempty"`
|
||||
Flatten bool `json:"flatten,omitempty"`
|
||||
Verify bool `json:"verify,omitempty"`
|
||||
ProjectSettingsFile string `json:"projectSettingsFile,omitempty"`
|
||||
GlobalSettingsFile string `json:"globalSettingsFile,omitempty"`
|
||||
M2Path string `json:"m2Path,omitempty"`
|
||||
LogSuccessfulMavenTransfers bool `json:"logSuccessfulMavenTransfers,omitempty"`
|
||||
CreateBOM bool `json:"createBOM,omitempty"`
|
||||
AltDeploymentRepositoryPassword string `json:"altDeploymentRepositoryPassword,omitempty"`
|
||||
AltDeploymentRepositoryUser string `json:"altDeploymentRepositoryUser,omitempty"`
|
||||
AltDeploymentRepositoryURL string `json:"altDeploymentRepositoryUrl,omitempty"`
|
||||
AltDeploymentRepositoryID string `json:"altDeploymentRepositoryID,omitempty"`
|
||||
CustomTLSCertificateLinks []string `json:"customTlsCertificateLinks,omitempty"`
|
||||
Publish bool `json:"publish,omitempty"`
|
||||
}
|
||||
|
||||
// MavenBuildCommand This step will install the maven project into the local maven repository.
|
||||
@@ -54,6 +60,7 @@ supports ci friendly versioning by flattening the pom before installing.`,
|
||||
log.SetErrorCategory(log.ErrorConfiguration)
|
||||
return err
|
||||
}
|
||||
log.RegisterSecret(stepConfig.AltDeploymentRepositoryPassword)
|
||||
|
||||
if len(GeneralConfig.HookConfig.SentryConfig.Dsn) > 0 {
|
||||
sentryHook := log.NewSentryHook(GeneralConfig.HookConfig.SentryConfig.Dsn, GeneralConfig.CorrelationID)
|
||||
@@ -108,6 +115,12 @@ func addMavenBuildFlags(cmd *cobra.Command, stepConfig *mavenBuildOptions) {
|
||||
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.")
|
||||
cmd.Flags().BoolVar(&stepConfig.CreateBOM, "createBOM", false, "Creates the bill of materials (BOM) using CycloneDX Maven plugin.")
|
||||
cmd.Flags().StringVar(&stepConfig.AltDeploymentRepositoryPassword, "altDeploymentRepositoryPassword", os.Getenv("PIPER_altDeploymentRepositoryPassword"), "Password for the alternative deployment repository to which the project artifacts should be deployed ( other than those specified in <distributionManagement> ). This password will be updated in settings.xml . When no settings.xml is provided a new one is created corresponding with <servers> tag")
|
||||
cmd.Flags().StringVar(&stepConfig.AltDeploymentRepositoryUser, "altDeploymentRepositoryUser", os.Getenv("PIPER_altDeploymentRepositoryUser"), "User for the alternative deployment repository to which the project artifacts should be deployed ( other than those specified in <distributionManagement> ). This user will be updated in settings.xml . When no settings.xml is provided a new one is created corresponding with <servers> tag")
|
||||
cmd.Flags().StringVar(&stepConfig.AltDeploymentRepositoryURL, "altDeploymentRepositoryUrl", os.Getenv("PIPER_altDeploymentRepositoryUrl"), "Url for the alternative deployment repository to which the project artifacts should be deployed ( other than those specified in <distributionManagement> ). This Url will be updated in settings.xml . When no settings.xml is provided a new one is created corresponding with <servers> tag")
|
||||
cmd.Flags().StringVar(&stepConfig.AltDeploymentRepositoryID, "altDeploymentRepositoryID", os.Getenv("PIPER_altDeploymentRepositoryID"), "Id for the alternative deployment repository to which the project artifacts should be deployed ( other than those specified in <distributionManagement> ). This id will be updated in settings.xml and will be used as a flag with DaltDeploymentRepository along with mavenAltDeploymentRepositoryUrl during maven deploy . When no settings.xml is provided a new one is created corresponding with <servers> tag")
|
||||
cmd.Flags().StringSliceVar(&stepConfig.CustomTLSCertificateLinks, "customTlsCertificateLinks", []string{}, "List of download links to custom TLS certificates. This is required to ensure trusted connections to instances with repositories (like nexus) when publish flag is set to true.")
|
||||
cmd.Flags().BoolVar(&stepConfig.Publish, "publish", false, "Configures maven to run the deploy plugin to publish artifacts to a repository.")
|
||||
|
||||
}
|
||||
|
||||
@@ -155,12 +168,17 @@ func mavenBuildMetadata() config.StepData {
|
||||
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: "globalSettingsFile",
|
||||
ResourceRef: []config.ResourceReference{
|
||||
{
|
||||
Name: "commonPipelineEnvironment",
|
||||
Param: "custom/mavenGlobalSettingsFile",
|
||||
},
|
||||
},
|
||||
Scope: []string{"GENERAL", "STEPS", "STAGES", "PARAMETERS"},
|
||||
Type: "string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{{Name: "maven/globalSettingsFile"}},
|
||||
},
|
||||
{
|
||||
Name: "m2Path",
|
||||
@@ -186,6 +204,85 @@ func mavenBuildMetadata() config.StepData {
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{{Name: "maven/createBOM"}},
|
||||
},
|
||||
{
|
||||
Name: "altDeploymentRepositoryPassword",
|
||||
ResourceRef: []config.ResourceReference{
|
||||
{
|
||||
Name: "commonPipelineEnvironment",
|
||||
Param: "custom/repositoryPassword",
|
||||
},
|
||||
|
||||
{
|
||||
Name: "altDeploymentRepositoryPasswordId",
|
||||
Type: "secret",
|
||||
},
|
||||
|
||||
{
|
||||
Name: "",
|
||||
Paths: []string{"$(vaultPath)/alt-deployment-repository-passowrd", "$(vaultBasePath)/$(vaultPipelineName)/alt-deployment-repository-passowrd", "$(vaultBasePath)/GROUP-SECRETS/alt-deployment-repository-passowrd"},
|
||||
Type: "vaultSecretFile",
|
||||
},
|
||||
},
|
||||
Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"},
|
||||
Type: "string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{},
|
||||
},
|
||||
{
|
||||
Name: "altDeploymentRepositoryUser",
|
||||
ResourceRef: []config.ResourceReference{
|
||||
{
|
||||
Name: "commonPipelineEnvironment",
|
||||
Param: "custom/repositoryUsername",
|
||||
},
|
||||
},
|
||||
Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"},
|
||||
Type: "string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{},
|
||||
},
|
||||
{
|
||||
Name: "altDeploymentRepositoryUrl",
|
||||
ResourceRef: []config.ResourceReference{
|
||||
{
|
||||
Name: "commonPipelineEnvironment",
|
||||
Param: "custom/repositoryUrl",
|
||||
},
|
||||
},
|
||||
Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"},
|
||||
Type: "string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{},
|
||||
},
|
||||
{
|
||||
Name: "altDeploymentRepositoryID",
|
||||
ResourceRef: []config.ResourceReference{
|
||||
{
|
||||
Name: "commonPipelineEnvironment",
|
||||
Param: "custom/repositoryId",
|
||||
},
|
||||
},
|
||||
Scope: []string{"GENERAL", "PARAMETERS", "STAGES", "STEPS"},
|
||||
Type: "string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{},
|
||||
},
|
||||
{
|
||||
Name: "customTlsCertificateLinks",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"PARAMETERS", "STAGES", "STEPS"},
|
||||
Type: "[]string",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{},
|
||||
},
|
||||
{
|
||||
Name: "publish",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"STEPS", "STAGES", "PARAMETERS"},
|
||||
Type: "bool",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{{Name: "maven/publish"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
Containers: []config.Container{
|
||||
|
||||
@@ -77,4 +77,43 @@ func TestMavenBuild(t *testing.T) {
|
||||
assert.Contains(t, mockedUtils.Calls[0].Params, "-DoutputFormat=xml")
|
||||
})
|
||||
|
||||
t.Run("mavenBuild include install and deploy when publish is true", func(t *testing.T) {
|
||||
mockedUtils := newMavenMockUtils()
|
||||
|
||||
config := mavenBuildOptions{Publish: true, Verify: false}
|
||||
|
||||
err := runMavenBuild(&config, nil, &mockedUtils)
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.Contains(t, mockedUtils.Calls[0].Params, "install")
|
||||
assert.NotContains(t, mockedUtils.Calls[0].Params, "verify")
|
||||
assert.Contains(t, mockedUtils.Calls[1].Params, "deploy")
|
||||
|
||||
})
|
||||
|
||||
t.Run("mavenBuild with deploy must skip build, install and test", func(t *testing.T) {
|
||||
mockedUtils := newMavenMockUtils()
|
||||
|
||||
config := mavenBuildOptions{Publish: true, Verify: false}
|
||||
|
||||
err := runMavenBuild(&config, nil, &mockedUtils)
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.Contains(t, mockedUtils.Calls[1].Params, "-Dmaven.main.skip=true")
|
||||
assert.Contains(t, mockedUtils.Calls[1].Params, "-Dmaven.test.skip=true")
|
||||
assert.Contains(t, mockedUtils.Calls[1].Params, "-Dmaven.install.skip=true")
|
||||
|
||||
})
|
||||
|
||||
t.Run("mavenBuild with deploy must include alt repo id and url when passed as parameter", func(t *testing.T) {
|
||||
mockedUtils := newMavenMockUtils()
|
||||
|
||||
config := mavenBuildOptions{Publish: true, Verify: false, AltDeploymentRepositoryID: "ID", AltDeploymentRepositoryURL: "http://sampleRepo.com"}
|
||||
|
||||
err := runMavenBuild(&config, nil, &mockedUtils)
|
||||
|
||||
assert.Nil(t, err)
|
||||
assert.Contains(t, mockedUtils.Calls[1].Params, "-DaltDeploymentRepository=ID::default::http://sampleRepo.com")
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user