github.com/xgoffin/jenkins-library@v1.154.0/cmd/mavenBuild.go (about)

     1  package cmd
     2  
     3  import (
     4  	"io/ioutil"
     5  	"os"
     6  	"path"
     7  	"path/filepath"
     8  	"strings"
     9  
    10  	"github.com/SAP/jenkins-library/pkg/buildsettings"
    11  	"github.com/SAP/jenkins-library/pkg/command"
    12  	"github.com/SAP/jenkins-library/pkg/log"
    13  	"github.com/SAP/jenkins-library/pkg/maven"
    14  	"github.com/SAP/jenkins-library/pkg/piperutils"
    15  	"github.com/SAP/jenkins-library/pkg/telemetry"
    16  	"github.com/pkg/errors"
    17  
    18  	piperhttp "github.com/SAP/jenkins-library/pkg/http"
    19  )
    20  
    21  func mavenBuild(config mavenBuildOptions, telemetryData *telemetry.CustomData, commonPipelineEnvironment *mavenBuildCommonPipelineEnvironment) {
    22  	utils := maven.NewUtilsBundle()
    23  
    24  	err := runMavenBuild(&config, telemetryData, utils, commonPipelineEnvironment)
    25  	if err != nil {
    26  		log.Entry().WithError(err).Fatal("step execution failed")
    27  	}
    28  }
    29  
    30  func runMavenBuild(config *mavenBuildOptions, telemetryData *telemetry.CustomData, utils maven.Utils, commonPipelineEnvironment *mavenBuildCommonPipelineEnvironment) error {
    31  
    32  	var flags = []string{"-update-snapshots", "--batch-mode"}
    33  
    34  	if len(config.Profiles) > 0 {
    35  		flags = append(flags, "--activate-profiles", strings.Join(config.Profiles, ","))
    36  	}
    37  
    38  	exists, _ := utils.FileExists("integration-tests/pom.xml")
    39  	if exists {
    40  		flags = append(flags, "-pl", "!integration-tests")
    41  	}
    42  
    43  	var defines []string
    44  	var goals []string
    45  
    46  	if config.Flatten {
    47  		goals = append(goals, "flatten:flatten")
    48  		defines = append(defines, "-Dflatten.mode=resolveCiFriendliesOnly", "-DupdatePomFile=true")
    49  	}
    50  
    51  	if config.CreateBOM {
    52  		goals = append(goals, "org.cyclonedx:cyclonedx-maven-plugin:makeAggregateBom")
    53  		createBOMConfig := []string{
    54  			"-DschemaVersion=1.2",
    55  			"-DincludeBomSerialNumber=true",
    56  			"-DincludeCompileScope=true",
    57  			"-DincludeProvidedScope=true",
    58  			"-DincludeRuntimeScope=true",
    59  			"-DincludeSystemScope=true",
    60  			"-DincludeTestScope=false",
    61  			"-DincludeLicenseText=false",
    62  			"-DoutputFormat=xml",
    63  		}
    64  		defines = append(defines, createBOMConfig...)
    65  	}
    66  
    67  	goals = append(goals, "org.jacoco:jacoco-maven-plugin:prepare-agent")
    68  
    69  	if config.Verify {
    70  		goals = append(goals, "verify")
    71  	} else {
    72  		goals = append(goals, "install")
    73  	}
    74  
    75  	mavenOptions := maven.ExecuteOptions{
    76  		Flags:                       flags,
    77  		Goals:                       goals,
    78  		Defines:                     defines,
    79  		PomPath:                     config.PomPath,
    80  		ProjectSettingsFile:         config.ProjectSettingsFile,
    81  		GlobalSettingsFile:          config.GlobalSettingsFile,
    82  		M2Path:                      config.M2Path,
    83  		LogSuccessfulMavenTransfers: config.LogSuccessfulMavenTransfers,
    84  	}
    85  
    86  	_, err := maven.Execute(&mavenOptions, utils)
    87  
    88  	if err != nil {
    89  		return errors.Wrapf(err, "failed to execute maven build for goal(s) '%v'", goals)
    90  	}
    91  
    92  	log.Entry().Debugf("creating build settings information...")
    93  	stepName := "mavenBuild"
    94  	dockerImage, err := GetDockerImageValue(stepName)
    95  	if err != nil {
    96  		return err
    97  	}
    98  
    99  	mavenConfig := buildsettings.BuildOptions{
   100  		Profiles:                    config.Profiles,
   101  		GlobalSettingsFile:          config.GlobalSettingsFile,
   102  		LogSuccessfulMavenTransfers: config.LogSuccessfulMavenTransfers,
   103  		CreateBOM:                   config.CreateBOM,
   104  		Publish:                     config.Publish,
   105  		BuildSettingsInfo:           config.BuildSettingsInfo,
   106  		DockerImage:                 dockerImage,
   107  	}
   108  	buildSettingsInfo, err := buildsettings.CreateBuildSettingsInfo(&mavenConfig, stepName)
   109  	if err != nil {
   110  		log.Entry().Warnf("failed to create build settings info: %v", err)
   111  	}
   112  	commonPipelineEnvironment.custom.buildSettingsInfo = buildSettingsInfo
   113  
   114  	if err == nil {
   115  		if config.Publish && !config.Verify {
   116  			log.Entry().Infof("publish detected, running mvn deploy")
   117  
   118  			if (len(config.AltDeploymentRepositoryID) > 0) && (len(config.AltDeploymentRepositoryPassword) > 0) && (len(config.AltDeploymentRepositoryUser) > 0) {
   119  				projectSettingsFilePath, err := createOrUpdateProjectSettingsXML(config.ProjectSettingsFile, config.AltDeploymentRepositoryID, config.AltDeploymentRepositoryUser, config.AltDeploymentRepositoryPassword, utils)
   120  				if err != nil {
   121  					return errors.Wrap(err, "Could not create or update project settings xml")
   122  				}
   123  				mavenOptions.ProjectSettingsFile = projectSettingsFilePath
   124  			}
   125  
   126  			deployFlags := []string{"-Dmaven.main.skip=true", "-Dmaven.test.skip=true", "-Dmaven.install.skip=true"}
   127  			if (len(config.AltDeploymentRepositoryID) > 0) && (len(config.AltDeploymentRepositoryURL) > 0) {
   128  				deployFlags = append(deployFlags, "-DaltDeploymentRepository="+config.AltDeploymentRepositoryID+"::default::"+config.AltDeploymentRepositoryURL)
   129  			}
   130  
   131  			downloadClient := &piperhttp.Client{}
   132  			runner := &command.Command{}
   133  			fileUtils := &piperutils.Files{}
   134  			if len(config.CustomTLSCertificateLinks) > 0 {
   135  				if err := loadRemoteRepoCertificates(config.CustomTLSCertificateLinks, downloadClient, &deployFlags, runner, fileUtils, config.JavaCaCertFilePath); err != nil {
   136  					log.SetErrorCategory(log.ErrorInfrastructure)
   137  					return err
   138  				}
   139  			}
   140  
   141  			mavenOptions.Flags = deployFlags
   142  			mavenOptions.Goals = []string{"deploy"}
   143  			mavenOptions.Defines = []string{}
   144  			_, err := maven.Execute(&mavenOptions, utils)
   145  			return err
   146  		} else {
   147  			log.Entry().Infof("publish not detected, ignoring maven deploy")
   148  		}
   149  	}
   150  
   151  	return err
   152  }
   153  
   154  func createOrUpdateProjectSettingsXML(projectSettingsFile string, altDeploymentRepositoryID string, altDeploymentRepositoryUser string, altDeploymentRepositoryPassword string, utils maven.Utils) (string, error) {
   155  	if len(projectSettingsFile) > 0 {
   156  		projectSettingsFilePath, err := maven.UpdateProjectSettingsXML(projectSettingsFile, altDeploymentRepositoryID, altDeploymentRepositoryUser, altDeploymentRepositoryPassword, utils)
   157  		if err != nil {
   158  			return "", errors.Wrap(err, "Could not update settings xml")
   159  		}
   160  		return projectSettingsFilePath, nil
   161  	} else {
   162  		projectSettingsFilePath, err := maven.CreateNewProjectSettingsXML(altDeploymentRepositoryID, altDeploymentRepositoryUser, altDeploymentRepositoryPassword, utils)
   163  		if err != nil {
   164  			return "", errors.Wrap(err, "Could not create settings xml")
   165  		}
   166  		return projectSettingsFilePath, nil
   167  	}
   168  }
   169  
   170  func loadRemoteRepoCertificates(certificateList []string, client piperhttp.Downloader, flags *[]string, runner command.ExecRunner, fileUtils piperutils.FileUtils, javaCaCertFilePath string) error {
   171  	//TODO: make use of java/keytool package
   172  	existingJavaCaCerts := filepath.Join(os.Getenv("JAVA_HOME"), "jre", "lib", "security", "cacerts")
   173  
   174  	if len(javaCaCertFilePath) > 0 {
   175  		existingJavaCaCerts = javaCaCertFilePath
   176  	}
   177  
   178  	exists, err := fileUtils.FileExists(existingJavaCaCerts)
   179  
   180  	if err != nil {
   181  		return errors.Wrap(err, "Could not find the existing java cacerts")
   182  	}
   183  
   184  	if !exists {
   185  		return errors.Wrap(err, "Could not find the existing java cacerts")
   186  	}
   187  
   188  	trustStore := filepath.Join(getWorkingDirForTrustStore(), ".pipeline", "mavenCaCerts")
   189  
   190  	log.Entry().Infof("copying java cacerts : %s to new cacerts : %s", existingJavaCaCerts, trustStore)
   191  	_, fileUtilserr := fileUtils.Copy(existingJavaCaCerts, trustStore)
   192  
   193  	if fileUtilserr != nil {
   194  		return errors.Wrap(err, "Could not copy existing cacerts into new cacerts location ")
   195  	}
   196  
   197  	log.Entry().Infof("using trust store %s", trustStore)
   198  
   199  	if exists, _ := fileUtils.FileExists(trustStore); exists {
   200  		maven_opts := "-Djavax.net.ssl.trustStore=.pipeline/mavenCaCerts -Djavax.net.ssl.trustStorePassword=changeit"
   201  		err := os.Setenv("MAVEN_OPTS", maven_opts)
   202  		if err != nil {
   203  			return errors.Wrap(err, "Could not create MAVEN_OPTS environment variable ")
   204  		}
   205  		log.Entry().WithField("trust store", trustStore).Info("Using local trust store")
   206  	}
   207  
   208  	if len(certificateList) > 0 {
   209  		keytoolOptions := []string{
   210  			"-import",
   211  			"-noprompt",
   212  			"-storepass", "changeit",
   213  			"-keystore", trustStore,
   214  		}
   215  		tmpFolder := getTempDirForCertFile()
   216  		defer os.RemoveAll(tmpFolder) // clean up
   217  
   218  		for _, certificate := range certificateList {
   219  			filename := path.Base(certificate) // decode?
   220  			target := filepath.Join(tmpFolder, filename)
   221  
   222  			log.Entry().WithField("source", certificate).WithField("target", target).Info("Downloading TLS certificate")
   223  			// download certificate
   224  			if err := client.DownloadFile(certificate, target, nil, nil); err != nil {
   225  				return errors.Wrapf(err, "Download of TLS certificate failed")
   226  			}
   227  			options := append(keytoolOptions, "-file", target)
   228  			options = append(options, "-alias", filename)
   229  			// add certificate to keystore
   230  			if err := runner.RunExecutable("keytool", options...); err != nil {
   231  				return errors.Wrap(err, "Adding certificate to keystore failed")
   232  			}
   233  		}
   234  		log.Entry().Infof("custom tls certificates successfully added to the trust store %s", trustStore)
   235  	} else {
   236  		log.Entry().Debug("Download of TLS certificates skipped")
   237  	}
   238  	return nil
   239  }
   240  
   241  func getWorkingDirForTrustStore() string {
   242  	workingDir, err := os.Getwd()
   243  	if err != nil {
   244  		log.Entry().WithError(err).WithField("path", workingDir).Debug("Retrieving of work directory failed")
   245  	}
   246  	return workingDir
   247  }
   248  
   249  func getTempDirForCertFile() string {
   250  	tmpFolder, err := ioutil.TempDir(".", "temp-")
   251  	if err != nil {
   252  		log.Entry().WithError(err).WithField("path", tmpFolder).Debug("Creating temp directory failed")
   253  	}
   254  	return tmpFolder
   255  }