mirror of
https://github.com/SAP/jenkins-library.git
synced 2025-01-16 05:16:08 +02:00
feat: add build artifacts metadata for mtaBuild (#5166)
This commit is contained in:
parent
da609e1536
commit
6988f43f7f
@ -41,7 +41,7 @@ func mavenBuild(config mavenBuildOptions, telemetryData *telemetry.CustomData, c
|
||||
}
|
||||
|
||||
func runMakeBOMGoal(config *mavenBuildOptions, utils maven.Utils) error {
|
||||
var flags = []string{"-update-snapshots", "--batch-mode"}
|
||||
flags := []string{"-update-snapshots", "--batch-mode"}
|
||||
if len(config.Profiles) > 0 {
|
||||
flags = append(flags, "--activate-profiles", strings.Join(config.Profiles, ","))
|
||||
}
|
||||
@ -89,8 +89,7 @@ func runMakeBOMGoal(config *mavenBuildOptions, utils maven.Utils) error {
|
||||
}
|
||||
|
||||
func runMavenBuild(config *mavenBuildOptions, _ *telemetry.CustomData, utils maven.Utils, commonPipelineEnvironment *mavenBuildCommonPipelineEnvironment) error {
|
||||
|
||||
var flags = []string{"-update-snapshots", "--batch-mode"}
|
||||
flags := []string{"-update-snapshots", "--batch-mode"}
|
||||
|
||||
if len(config.Profiles) > 0 {
|
||||
flags = append(flags, "--activate-profiles", strings.Join(config.Profiles, ","))
|
||||
@ -255,7 +254,7 @@ func createBuildArtifactsMetadata(config *mavenBuildOptions, commonPipelineEnvir
|
||||
} else {
|
||||
coordinate.BuildPath = filepath.Dir(match)
|
||||
coordinate.URL = config.AltDeploymentRepositoryURL
|
||||
coordinate.PURL = getPurlForThePom(match)
|
||||
coordinate.PURL = piperutils.GetPurl(filepath.Join(filepath.Dir(match), "/target/"+mvnSimpleBomFilename+".xml"))
|
||||
buildCoordinates = append(buildCoordinates, coordinate)
|
||||
}
|
||||
}
|
||||
@ -274,25 +273,6 @@ func createBuildArtifactsMetadata(config *mavenBuildOptions, commonPipelineEnvir
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func getPurlForThePom(pomFilePath string) string {
|
||||
bomPath := filepath.Join(filepath.Dir(pomFilePath) + "/target/" + mvnSimpleBomFilename + ".xml")
|
||||
exists, _ := piperutils.FileExists(bomPath)
|
||||
if !exists {
|
||||
log.Entry().Debugf("bom file doesn't exist and hence no pURL info: %v", bomPath)
|
||||
return ""
|
||||
}
|
||||
bom, err := piperutils.GetBom(bomPath)
|
||||
if err != nil {
|
||||
log.Entry().Warnf("failed to get bom file %s: %v", bomPath, err)
|
||||
return ""
|
||||
}
|
||||
|
||||
log.Entry().Debugf("Found purl: %s for the bomPath: %s", bom.Metadata.Component.Purl, bomPath)
|
||||
purl := bom.Metadata.Component.Purl
|
||||
|
||||
return purl
|
||||
}
|
||||
|
||||
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)
|
||||
@ -310,7 +290,7 @@ func createOrUpdateProjectSettingsXML(projectSettingsFile string, altDeploymentR
|
||||
}
|
||||
|
||||
func loadRemoteRepoCertificates(certificateList []string, client piperhttp.Downloader, flags *[]string, runner command.ExecRunner, fileUtils piperutils.FileUtils, javaCaCertFilePath string) error {
|
||||
//TODO: make use of java/keytool package
|
||||
// TODO: make use of java/keytool package
|
||||
existingJavaCaCerts := filepath.Join(os.Getenv("JAVA_HOME"), "jre", "lib", "security", "cacerts")
|
||||
|
||||
if len(javaCaCertFilePath) > 0 {
|
||||
@ -318,7 +298,6 @@ func loadRemoteRepoCertificates(certificateList []string, client piperhttp.Downl
|
||||
}
|
||||
|
||||
exists, err := fileUtils.FileExists(existingJavaCaCerts)
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Could not find the existing java cacerts")
|
||||
}
|
||||
|
@ -4,18 +4,14 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/SAP/jenkins-library/pkg/piperutils"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var cpe mavenBuildCommonPipelineEnvironment
|
||||
|
||||
func TestMavenBuild(t *testing.T) {
|
||||
|
||||
t.Run("mavenBuild should install the artifact", func(t *testing.T) {
|
||||
mockedUtils := newMavenMockUtils()
|
||||
|
||||
@ -123,54 +119,4 @@ func TestMavenBuild(t *testing.T) {
|
||||
assert.Equal(t, mockedUtils.Calls[0].Exec, "mvn")
|
||||
assert.Empty(t, cpe.custom.mavenBuildArtifacts)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func createTempFile(t *testing.T, dir string, filename string, content string) string {
|
||||
filePath := filepath.Join(dir, filename)
|
||||
err := os.WriteFile(filePath, []byte(content), 0666)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp file: %s", err)
|
||||
}
|
||||
return filePath
|
||||
}
|
||||
|
||||
func TestGetPurlForThePomAndDeleteIndividualBom(t *testing.T) {
|
||||
|
||||
t.Run("valid BOM file, aggregated BOM", func(t *testing.T) {
|
||||
tempDir, err := piperutils.Files{}.TempDir("", "test")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp directory: %s", err)
|
||||
}
|
||||
|
||||
bomContent := `<bom>
|
||||
<metadata>
|
||||
<component>
|
||||
<purl>pkg:maven/com.example/aggregatecomponent@1.0.0</purl>
|
||||
</component>
|
||||
<properties>
|
||||
<property name="maven.goal" value="makeAggregateBom" />
|
||||
</properties>
|
||||
</metadata>
|
||||
</bom>`
|
||||
pomFilePath := createTempFile(t, tempDir, "pom.xml", "")
|
||||
bomDir := filepath.Join(tempDir, "target")
|
||||
if err := os.MkdirAll(bomDir, 0777); err != nil {
|
||||
t.Fatalf("Failed to create temp directory: %s", err)
|
||||
}
|
||||
bomFilePath := createTempFile(t, bomDir, mvnSimpleBomFilename+".xml", bomContent)
|
||||
|
||||
purl := getPurlForThePom(pomFilePath)
|
||||
assert.Equal(t, "pkg:maven/com.example/aggregatecomponent@1.0.0", purl)
|
||||
_, err = os.Stat(bomFilePath)
|
||||
assert.False(t, os.IsNotExist(err)) // File should not be deleted
|
||||
})
|
||||
|
||||
t.Run("BOM file does not exist", func(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
pomFilePath := createTempFile(t, tempDir, "pom.xml", "") // Create a temp pom file
|
||||
|
||||
purl := getPurlForThePom(pomFilePath)
|
||||
assert.Equal(t, "", purl)
|
||||
})
|
||||
}
|
||||
|
212
cmd/mtaBuild.go
212
cmd/mtaBuild.go
@ -5,6 +5,7 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
@ -14,8 +15,10 @@ import (
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/SAP/jenkins-library/pkg/build"
|
||||
"github.com/SAP/jenkins-library/pkg/buildsettings"
|
||||
"github.com/SAP/jenkins-library/pkg/npm"
|
||||
"github.com/SAP/jenkins-library/pkg/versioning"
|
||||
|
||||
"github.com/SAP/jenkins-library/pkg/command"
|
||||
piperhttp "github.com/SAP/jenkins-library/pkg/http"
|
||||
@ -53,7 +56,7 @@ const (
|
||||
NEO MTABuildTarget = iota
|
||||
// CF ...
|
||||
CF MTABuildTarget = iota
|
||||
//XSA ...
|
||||
// XSA ...
|
||||
XSA MTABuildTarget = iota
|
||||
)
|
||||
|
||||
@ -67,7 +70,7 @@ func ValueOfBuildTarget(str string) (MTABuildTarget, error) {
|
||||
case "XSA":
|
||||
return XSA, nil
|
||||
default:
|
||||
return -1, fmt.Errorf("Unknown Platform: '%s'", str)
|
||||
return -1, fmt.Errorf("unknown platform: '%s'", str)
|
||||
}
|
||||
}
|
||||
|
||||
@ -94,6 +97,9 @@ type mtaBuildUtils interface {
|
||||
|
||||
SetNpmRegistries(defaultNpmRegistry string) error
|
||||
InstallAllDependencies(defaultNpmRegistry string) error
|
||||
|
||||
Open(name string) (io.ReadWriteCloser, error)
|
||||
SendRequest(method, url string, body io.Reader, header http.Header, cookies []*http.Cookie) (*http.Response, error)
|
||||
}
|
||||
|
||||
type mtaBuildUtilsBundle struct {
|
||||
@ -131,9 +137,7 @@ func newMtaBuildUtilsBundle() mtaBuildUtils {
|
||||
return &utils
|
||||
}
|
||||
|
||||
func mtaBuild(config mtaBuildOptions,
|
||||
telemetryData *telemetry.CustomData,
|
||||
commonPipelineEnvironment *mtaBuildCommonPipelineEnvironment) {
|
||||
func mtaBuild(config mtaBuildOptions, _ *telemetry.CustomData, commonPipelineEnvironment *mtaBuildCommonPipelineEnvironment) {
|
||||
log.Entry().Debugf("Launching mta build")
|
||||
utils := newMtaBuildUtilsBundle()
|
||||
|
||||
@ -145,39 +149,31 @@ func mtaBuild(config mtaBuildOptions,
|
||||
}
|
||||
}
|
||||
|
||||
func runMtaBuild(config mtaBuildOptions,
|
||||
commonPipelineEnvironment *mtaBuildCommonPipelineEnvironment,
|
||||
utils mtaBuildUtils) error {
|
||||
|
||||
var err error
|
||||
|
||||
err = handleSettingsFiles(config, utils)
|
||||
if err != nil {
|
||||
func runMtaBuild(config mtaBuildOptions, commonPipelineEnvironment *mtaBuildCommonPipelineEnvironment, utils mtaBuildUtils) error {
|
||||
if err := handleSettingsFiles(config, utils); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = handleActiveProfileUpdate(config, utils)
|
||||
if err != nil {
|
||||
if err := handleActiveProfileUpdate(config, utils); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = utils.SetNpmRegistries(config.DefaultNpmRegistry)
|
||||
if err := utils.SetNpmRegistries(config.DefaultNpmRegistry); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mtaYamlFile := filepath.Join(getSourcePath(config), "mta.yaml")
|
||||
mtaYamlFileExists, err := utils.FileExists(mtaYamlFile)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !mtaYamlFileExists {
|
||||
|
||||
if err = createMtaYamlFile(mtaYamlFile, config.ApplicationName, utils); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
} else {
|
||||
log.Entry().Infof("\"%s\" file found in project sources", mtaYamlFile)
|
||||
log.Entry().Infof(`"%s" file found in project sources`, mtaYamlFile)
|
||||
}
|
||||
|
||||
if config.EnableSetTimestamp {
|
||||
@ -187,20 +183,17 @@ func runMtaBuild(config mtaBuildOptions,
|
||||
}
|
||||
|
||||
mtarName, isMtarNativelySuffixed, err := getMtarName(config, mtaYamlFile, utils)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var call []string
|
||||
|
||||
platform, err := ValueOfBuildTarget(config.Platform)
|
||||
if err != nil {
|
||||
log.SetErrorCategory(log.ErrorConfiguration)
|
||||
return err
|
||||
}
|
||||
|
||||
call = append(call, "mbt", "build", "--mtar", mtarName, "--platform", platform.String())
|
||||
call := []string{"mbt", "build", "--mtar", mtarName, "--platform", platform.String()}
|
||||
if len(config.Extensions) != 0 {
|
||||
call = append(call, fmt.Sprintf("--extensions=%s", config.Extensions))
|
||||
}
|
||||
@ -229,7 +222,7 @@ func runMtaBuild(config mtaBuildOptions,
|
||||
utils.AppendEnv([]string{"MAVEN_OPTS=-Dmaven.repo.local=" + absolutePath})
|
||||
}
|
||||
|
||||
log.Entry().Infof("Executing mta build call: \"%s\"", strings.Join(call, " "))
|
||||
log.Entry().Infof(`Executing mta build call: "%s"`, strings.Join(call, " "))
|
||||
|
||||
if err := utils.RunExecutable(call[0], call[1:]...); err != nil {
|
||||
log.SetErrorCategory(log.ErrorBuild)
|
||||
@ -261,65 +254,97 @@ func runMtaBuild(config mtaBuildOptions,
|
||||
commonPipelineEnvironment.custom.mtaBuildToolDesc = filepath.ToSlash(mtaYamlFile)
|
||||
|
||||
if config.InstallArtifacts {
|
||||
// install maven artifacts in local maven repo because `mbt build` executes `mvn package -B`
|
||||
err = installMavenArtifacts(utils, config)
|
||||
if err != nil {
|
||||
if err = installMavenArtifacts(utils, config); err != nil {
|
||||
return err
|
||||
}
|
||||
// mta-builder executes 'npm install --production', therefore we need 'npm ci/install' to install the dev-dependencies
|
||||
err = utils.InstallAllDependencies(config.DefaultNpmRegistry)
|
||||
if err != nil {
|
||||
if err = utils.InstallAllDependencies(config.DefaultNpmRegistry); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if config.Publish {
|
||||
log.Entry().Infof("publish detected")
|
||||
if (len(config.MtaDeploymentRepositoryPassword) > 0) && (len(config.MtaDeploymentRepositoryUser) > 0) &&
|
||||
(len(config.MtaDeploymentRepositoryURL) > 0) {
|
||||
if (len(config.MtarGroup) > 0) && (len(config.Version) > 0) {
|
||||
httpClient := &piperhttp.Client{}
|
||||
|
||||
credentialsEncoded := "Basic " + base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", config.MtaDeploymentRepositoryUser, config.MtaDeploymentRepositoryPassword)))
|
||||
headers := http.Header{}
|
||||
headers.Add("Authorization", credentialsEncoded)
|
||||
|
||||
config.MtarGroup = strings.ReplaceAll(config.MtarGroup, ".", "/")
|
||||
|
||||
mtarArtifactName := mtarName
|
||||
|
||||
// only trim the .mtar suffix from the mtarName
|
||||
if !isMtarNativelySuffixed {
|
||||
mtarArtifactName = strings.TrimSuffix(mtarArtifactName, ".mtar")
|
||||
}
|
||||
|
||||
config.MtaDeploymentRepositoryURL += config.MtarGroup + "/" + mtarArtifactName + "/" + config.Version + "/" + fmt.Sprintf("%v-%v.%v", mtarArtifactName, config.Version, "mtar")
|
||||
|
||||
commonPipelineEnvironment.custom.mtarPublishedURL = config.MtaDeploymentRepositoryURL
|
||||
|
||||
log.Entry().Infof("pushing mtar artifact to repository : %s", config.MtaDeploymentRepositoryURL)
|
||||
|
||||
data, err := os.Open(getMtarFilePath(config, mtarName))
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to open mtar archive for upload")
|
||||
}
|
||||
_, httpErr := httpClient.SendRequest("PUT", config.MtaDeploymentRepositoryURL, data, headers, nil)
|
||||
|
||||
if httpErr != nil {
|
||||
return errors.Wrap(err, "failed to upload mtar to repository")
|
||||
}
|
||||
} else {
|
||||
return errors.New("mtarGroup, version not found and must be present")
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
return errors.New("mtaDeploymentRepositoryUser, mtaDeploymentRepositoryPassword and mtaDeploymentRepositoryURL not found , must be present")
|
||||
if err = handlePublish(config, commonPipelineEnvironment, utils, mtarName, isMtarNativelySuffixed); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
log.Entry().Infof("no publish detected, skipping upload of mtar artifact")
|
||||
}
|
||||
return err
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func handlePublish(config mtaBuildOptions, commonPipelineEnvironment *mtaBuildCommonPipelineEnvironment, utils mtaBuildUtils, mtarName string, isMtarNativelySuffixed bool) error {
|
||||
log.Entry().Infof("publish detected")
|
||||
|
||||
if len(config.MtaDeploymentRepositoryPassword) == 0 ||
|
||||
len(config.MtaDeploymentRepositoryUser) == 0 ||
|
||||
len(config.MtaDeploymentRepositoryURL) == 0 {
|
||||
return errors.New("mtaDeploymentRepositoryUser, mtaDeploymentRepositoryPassword and mtaDeploymentRepositoryURL not found, must be present")
|
||||
}
|
||||
|
||||
if len(config.MtarGroup) == 0 || len(config.Version) == 0 {
|
||||
return errors.New("mtarGroup, version not found and must be present")
|
||||
}
|
||||
|
||||
credentialsEncoded := "Basic " + base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", config.MtaDeploymentRepositoryUser, config.MtaDeploymentRepositoryPassword)))
|
||||
headers := http.Header{}
|
||||
headers.Add("Authorization", credentialsEncoded)
|
||||
|
||||
config.MtarGroup = strings.ReplaceAll(config.MtarGroup, ".", "/")
|
||||
mtarArtifactName := mtarName
|
||||
if !isMtarNativelySuffixed {
|
||||
mtarArtifactName = strings.TrimSuffix(mtarArtifactName, ".mtar")
|
||||
}
|
||||
|
||||
config.MtaDeploymentRepositoryURL += config.MtarGroup + "/" + mtarArtifactName + "/" + config.Version + "/" + fmt.Sprintf("%v-%v.%v", mtarArtifactName, config.Version, "mtar")
|
||||
commonPipelineEnvironment.custom.mtarPublishedURL = config.MtaDeploymentRepositoryURL
|
||||
|
||||
log.Entry().Infof("pushing mtar artifact to repository : %s", config.MtaDeploymentRepositoryURL)
|
||||
|
||||
mtarPath := getMtarFilePath(config, mtarName)
|
||||
data, err := utils.Open(mtarPath)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to open mtar archive for upload")
|
||||
}
|
||||
defer data.Close()
|
||||
|
||||
if _, httpErr := utils.SendRequest("PUT", config.MtaDeploymentRepositoryURL, data, headers, nil); httpErr != nil {
|
||||
return errors.Wrap(httpErr, "failed to upload mtar to repository")
|
||||
}
|
||||
|
||||
if config.CreateBuildArtifactsMetadata {
|
||||
if err := buildArtifactsMetadata(config, commonPipelineEnvironment, mtarPath); err != nil {
|
||||
log.Entry().Warnf("unable to create build artifacts metadata: %v", err)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildArtifactsMetadata(config mtaBuildOptions, commonPipelineEnvironment *mtaBuildCommonPipelineEnvironment, mtarPath string) error {
|
||||
mtarDir := filepath.Dir(mtarPath)
|
||||
buildArtifacts := build.BuildArtifacts{
|
||||
Coordinates: []versioning.Coordinates{
|
||||
{
|
||||
GroupID: config.MtarGroup,
|
||||
ArtifactID: config.MtarName,
|
||||
Version: config.Version,
|
||||
Packaging: "mtar",
|
||||
BuildPath: getSourcePath(config),
|
||||
URL: config.MtaDeploymentRepositoryURL,
|
||||
PURL: piperutils.GetPurl(filepath.Join(mtarDir, "sbom-gen/bom-mta.xml")),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
jsonResult, err := json.Marshal(buildArtifacts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal build artifacts: %v", err)
|
||||
}
|
||||
|
||||
commonPipelineEnvironment.custom.mtaBuildArtifacts = string(jsonResult)
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleActiveProfileUpdate(config mtaBuildOptions, utils mtaBuildUtils) error {
|
||||
@ -355,15 +380,12 @@ func addNpmBinToPath(utils mtaBuildUtils) error {
|
||||
}
|
||||
|
||||
func getMtarName(config mtaBuildOptions, mtaYamlFile string, utils mtaBuildUtils) (string, bool, error) {
|
||||
|
||||
mtarName := config.MtarName
|
||||
isMtarNativelySuffixed := false
|
||||
if len(mtarName) == 0 {
|
||||
|
||||
log.Entry().Debugf("mtar name not provided via config. Extracting from file \"%s\"", mtaYamlFile)
|
||||
log.Entry().Debugf(`mtar name not provided via config. Extracting from file "%s"`, mtaYamlFile)
|
||||
|
||||
mtaID, err := getMtaID(mtaYamlFile, utils)
|
||||
|
||||
if err != nil {
|
||||
log.SetErrorCategory(log.ErrorConfiguration)
|
||||
return "", isMtarNativelySuffixed, err
|
||||
@ -371,10 +393,10 @@ func getMtarName(config mtaBuildOptions, mtaYamlFile string, utils mtaBuildUtils
|
||||
|
||||
if len(mtaID) == 0 {
|
||||
log.SetErrorCategory(log.ErrorConfiguration)
|
||||
return "", isMtarNativelySuffixed, fmt.Errorf("Invalid mtar ID. Was empty")
|
||||
return "", isMtarNativelySuffixed, fmt.Errorf("invalid mtar ID. Was empty")
|
||||
}
|
||||
|
||||
log.Entry().Debugf("mtar name extracted from file \"%s\": \"%s\"", mtaYamlFile, mtaID)
|
||||
log.Entry().Debugf(`mtar name extracted from file "%s": "%s"`, mtaYamlFile, mtaID)
|
||||
|
||||
// there can be cases where the mtaId itself has the value com.myComapany.mtar , adding an extra .mtar causes .mtar.mtar
|
||||
if !strings.HasSuffix(mtaID, ".mtar") {
|
||||
@ -387,11 +409,9 @@ func getMtarName(config mtaBuildOptions, mtaYamlFile string, utils mtaBuildUtils
|
||||
}
|
||||
|
||||
return mtarName, isMtarNativelySuffixed, nil
|
||||
|
||||
}
|
||||
|
||||
func setTimeStamp(mtaYamlFile string, utils mtaBuildUtils) error {
|
||||
|
||||
mtaYaml, err := utils.FileRead(mtaYamlFile)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -406,9 +426,9 @@ func setTimeStamp(mtaYamlFile string, utils mtaBuildUtils) error {
|
||||
log.SetErrorCategory(log.ErrorConfiguration)
|
||||
return err
|
||||
}
|
||||
log.Entry().Infof("Timestamp replaced in \"%s\"", mtaYamlFile)
|
||||
log.Entry().Infof(`Timestamp replaced in "%s"`, mtaYamlFile)
|
||||
} else {
|
||||
log.Entry().Infof("No timestamp contained in \"%s\". File has not been modified.", mtaYamlFile)
|
||||
log.Entry().Infof(`No timestamp contained in "%s". File has not been modified.`, mtaYamlFile)
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -420,14 +440,16 @@ func getTimestamp() string {
|
||||
}
|
||||
|
||||
func createMtaYamlFile(mtaYamlFile, applicationName string, utils mtaBuildUtils) error {
|
||||
|
||||
log.Entry().Infof("\"%s\" file not found in project sources", mtaYamlFile)
|
||||
log.Entry().Infof(`"%s" file not found in project sources`, mtaYamlFile)
|
||||
|
||||
if len(applicationName) == 0 {
|
||||
return fmt.Errorf("'%[1]s' not found in project sources and 'applicationName' not provided as parameter - cannot generate '%[1]s' file", mtaYamlFile)
|
||||
}
|
||||
|
||||
packageFileExists, err := utils.FileExists("package.json")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !packageFileExists {
|
||||
return fmt.Errorf("package.json file does not exist")
|
||||
}
|
||||
@ -437,16 +459,18 @@ func createMtaYamlFile(mtaYamlFile, applicationName string, utils mtaBuildUtils)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
json.Unmarshal(pContent, &result)
|
||||
if err := json.Unmarshal(pContent, &result); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal package.json: %w", err)
|
||||
}
|
||||
|
||||
version, ok := result["version"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("Version not found in \"package.json\" (or wrong type)")
|
||||
return fmt.Errorf(`version not found in "package.json" (or wrong type)`)
|
||||
}
|
||||
|
||||
name, ok := result["name"].(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("Name not found in \"package.json\" (or wrong type)")
|
||||
return fmt.Errorf(`name not found in "package.json" (or wrong type)`)
|
||||
}
|
||||
|
||||
mtaConfig, err := generateMta(name, applicationName, version)
|
||||
@ -457,7 +481,7 @@ func createMtaYamlFile(mtaYamlFile, applicationName string, utils mtaBuildUtils)
|
||||
if err := utils.FileWrite(mtaYamlFile, []byte(mtaConfig), 0644); err != nil {
|
||||
return fmt.Errorf("failed to write %v: %w", mtaYamlFile, err)
|
||||
}
|
||||
log.Entry().Infof("\"%s\" created.", mtaYamlFile)
|
||||
log.Entry().Infof(`"%s" created.`, mtaYamlFile)
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -467,15 +491,14 @@ func handleSettingsFiles(config mtaBuildOptions, utils mtaBuildUtils) error {
|
||||
}
|
||||
|
||||
func generateMta(id, applicationName, version string) (string, error) {
|
||||
|
||||
if len(id) == 0 {
|
||||
return "", fmt.Errorf("Generating mta file: ID not provided")
|
||||
return "", fmt.Errorf("generating mta file: ID not provided")
|
||||
}
|
||||
if len(applicationName) == 0 {
|
||||
return "", fmt.Errorf("Generating mta file: ApplicationName not provided")
|
||||
return "", fmt.Errorf("generating mta file: ApplicationName not provided")
|
||||
}
|
||||
if len(version) == 0 {
|
||||
return "", fmt.Errorf("Generating mta file: Version not provided")
|
||||
return "", fmt.Errorf("generating mta file: Version not provided")
|
||||
}
|
||||
|
||||
tmpl, e := template.New("mta.yaml").Parse(templateMtaYml)
|
||||
@ -499,7 +522,6 @@ func generateMta(id, applicationName, version string) (string, error) {
|
||||
}
|
||||
|
||||
func getMtaID(mtaYamlFile string, utils mtaBuildUtils) (string, error) {
|
||||
|
||||
var result map[string]interface{}
|
||||
p, err := utils.FileRead(mtaYamlFile)
|
||||
if err != nil {
|
||||
@ -512,7 +534,7 @@ func getMtaID(mtaYamlFile string, utils mtaBuildUtils) (string, error) {
|
||||
|
||||
id, ok := result["ID"].(string)
|
||||
if !ok || len(id) == 0 {
|
||||
return "", fmt.Errorf("Id not found in mta yaml file (or wrong type)")
|
||||
return "", fmt.Errorf("id not found in mta yaml file (or wrong type)")
|
||||
}
|
||||
|
||||
return id, nil
|
||||
|
@ -45,6 +45,7 @@ type mtaBuildOptions struct {
|
||||
BuildSettingsInfo string `json:"buildSettingsInfo,omitempty"`
|
||||
CreateBOM bool `json:"createBOM,omitempty"`
|
||||
EnableSetTimestamp bool `json:"enableSetTimestamp,omitempty"`
|
||||
CreateBuildArtifactsMetadata bool `json:"createBuildArtifactsMetadata,omitempty"`
|
||||
}
|
||||
|
||||
type mtaBuildCommonPipelineEnvironment struct {
|
||||
@ -53,6 +54,7 @@ type mtaBuildCommonPipelineEnvironment struct {
|
||||
mtaBuildToolDesc string
|
||||
mtarPublishedURL string
|
||||
buildSettingsInfo string
|
||||
mtaBuildArtifacts string
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,6 +68,7 @@ func (p *mtaBuildCommonPipelineEnvironment) persist(path, resourceName string) {
|
||||
{category: "custom", name: "mtaBuildToolDesc", value: p.custom.mtaBuildToolDesc},
|
||||
{category: "custom", name: "mtarPublishedUrl", value: p.custom.mtarPublishedURL},
|
||||
{category: "custom", name: "buildSettingsInfo", value: p.custom.buildSettingsInfo},
|
||||
{category: "custom", name: "mtaBuildArtifacts", value: p.custom.mtaBuildArtifacts},
|
||||
}
|
||||
|
||||
errCount := 0
|
||||
@ -266,6 +269,7 @@ func addMtaBuildFlags(cmd *cobra.Command, stepConfig *mtaBuildOptions) {
|
||||
cmd.Flags().StringVar(&stepConfig.BuildSettingsInfo, "buildSettingsInfo", os.Getenv("PIPER_buildSettingsInfo"), "build settings info is typically filled by the step automatically to create information about the build settings that were used during the mta build . This information is typically used for compliance related processes.")
|
||||
cmd.Flags().BoolVar(&stepConfig.CreateBOM, "createBOM", false, "Creates the bill of materials (BOM) using CycloneDX plugin.")
|
||||
cmd.Flags().BoolVar(&stepConfig.EnableSetTimestamp, "enableSetTimestamp", true, "Enables setting the timestamp in the `mta.yaml` when it contains `${timestamp}`. Disable this when you want the MTA Deploy Service to do this instead.")
|
||||
cmd.Flags().BoolVar(&stepConfig.CreateBuildArtifactsMetadata, "createBuildArtifactsMetadata", false, "metadata about the artifacts that are build and published, this metadata is generally used by steps downstream in the pipeline")
|
||||
|
||||
}
|
||||
|
||||
@ -529,6 +533,15 @@ func mtaBuildMetadata() config.StepData {
|
||||
Aliases: []config.Alias{},
|
||||
Default: true,
|
||||
},
|
||||
{
|
||||
Name: "createBuildArtifactsMetadata",
|
||||
ResourceRef: []config.ResourceReference{},
|
||||
Scope: []string{"STEPS", "STAGES", "PARAMETERS"},
|
||||
Type: "bool",
|
||||
Mandatory: false,
|
||||
Aliases: []config.Alias{},
|
||||
Default: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
Containers: []config.Container{
|
||||
@ -544,6 +557,7 @@ func mtaBuildMetadata() config.StepData {
|
||||
{"name": "custom/mtaBuildToolDesc"},
|
||||
{"name": "custom/mtarPublishedUrl"},
|
||||
{"name": "custom/buildSettingsInfo"},
|
||||
{"name": "custom/mtaBuildArtifacts"},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -1,12 +1,15 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/SAP/jenkins-library/pkg/config"
|
||||
"github.com/SAP/jenkins-library/pkg/mock"
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@ -18,6 +21,8 @@ type mtaBuildTestUtilsBundle struct {
|
||||
projectSettingsFile string
|
||||
globalSettingsFile string
|
||||
registryUsedInSetNpmRegistries string
|
||||
openReturns string
|
||||
sendRequestReturns func() (*http.Response, error)
|
||||
}
|
||||
|
||||
func (m *mtaBuildTestUtilsBundle) SetNpmRegistries(defaultNpmRegistry string) error {
|
||||
@ -26,7 +31,7 @@ func (m *mtaBuildTestUtilsBundle) SetNpmRegistries(defaultNpmRegistry string) er
|
||||
}
|
||||
|
||||
func (m *mtaBuildTestUtilsBundle) InstallAllDependencies(defaultNpmRegistry string) error {
|
||||
return errors.New("Test should not install dependencies.") //TODO implement test
|
||||
return errors.New("Test should not install dependencies.") // TODO implement test
|
||||
}
|
||||
|
||||
func (m *mtaBuildTestUtilsBundle) DownloadAndCopySettingsFiles(globalSettingsFile string, projectSettingsFile string) error {
|
||||
@ -39,6 +44,36 @@ func (m *mtaBuildTestUtilsBundle) DownloadFile(url, filename string, header http
|
||||
return errors.New("Test should not download files.")
|
||||
}
|
||||
|
||||
func (m *mtaBuildTestUtilsBundle) Open(name string) (io.ReadWriteCloser, error) {
|
||||
if m.openReturns != "" {
|
||||
return NewMockReadCloser(m.openReturns), nil
|
||||
}
|
||||
return nil, errors.New("Test should not open files.")
|
||||
}
|
||||
|
||||
// MockReadCloser is a struct that implements io.ReadCloser
|
||||
type MockReadWriteCloser struct {
|
||||
io.Reader
|
||||
io.Writer
|
||||
}
|
||||
|
||||
// Close is a no-op method to satisfy the io.Closer interface
|
||||
func (m *MockReadWriteCloser) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewMockReadCloser returns a new MockReadCloser with the given data
|
||||
func NewMockReadCloser(data string) io.ReadWriteCloser {
|
||||
return &MockReadWriteCloser{Reader: bytes.NewBufferString(data)}
|
||||
}
|
||||
|
||||
func (m *mtaBuildTestUtilsBundle) SendRequest(method, url string, body io.Reader, header http.Header, cookies []*http.Cookie) (*http.Response, error) {
|
||||
if m.sendRequestReturns != nil {
|
||||
return m.sendRequestReturns()
|
||||
}
|
||||
return nil, errors.New("Test should not send requests.")
|
||||
}
|
||||
|
||||
func newMtaBuildTestUtilsBundle() *mtaBuildTestUtilsBundle {
|
||||
utilsBundle := mtaBuildTestUtilsBundle{
|
||||
ExecMockRunner: &mock.ExecMockRunner{},
|
||||
@ -48,11 +83,11 @@ func newMtaBuildTestUtilsBundle() *mtaBuildTestUtilsBundle {
|
||||
}
|
||||
|
||||
func TestMtaBuild(t *testing.T) {
|
||||
|
||||
cpe := mtaBuildCommonPipelineEnvironment{}
|
||||
|
||||
SetConfigOptions(ConfigCommandOptions{
|
||||
OpenFile: config.OpenPiperFile,
|
||||
})
|
||||
t.Run("Application name not set", func(t *testing.T) {
|
||||
|
||||
utilsMock := newMtaBuildTestUtilsBundle()
|
||||
options := mtaBuildOptions{}
|
||||
|
||||
@ -60,15 +95,20 @@ func TestMtaBuild(t *testing.T) {
|
||||
|
||||
assert.NotNil(t, err)
|
||||
assert.Equal(t, "'mta.yaml' not found in project sources and 'applicationName' not provided as parameter - cannot generate 'mta.yaml' file", err.Error())
|
||||
|
||||
})
|
||||
|
||||
t.Run("Provide default npm registry", func(t *testing.T) {
|
||||
|
||||
utilsMock := newMtaBuildTestUtilsBundle()
|
||||
options := mtaBuildOptions{ApplicationName: "myApp", Platform: "CF", DefaultNpmRegistry: "https://example.org/npm", MtarName: "myName", Source: "./", Target: "./"}
|
||||
options := mtaBuildOptions{
|
||||
ApplicationName: "myApp",
|
||||
Platform: "CF",
|
||||
DefaultNpmRegistry: "https://example.org/npm",
|
||||
MtarName: "myName",
|
||||
Source: "./",
|
||||
Target: "./",
|
||||
}
|
||||
|
||||
utilsMock.AddFile("package.json", []byte("{\"name\": \"myName\", \"version\": \"1.2.3\"}"))
|
||||
utilsMock.AddFile("package.json", []byte(`{"name": "myName", "version": "1.2.3"}`))
|
||||
|
||||
err := runMtaBuild(options, &cpe, utilsMock)
|
||||
|
||||
@ -78,7 +118,6 @@ func TestMtaBuild(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Package json does not exist", func(t *testing.T) {
|
||||
|
||||
utilsMock := newMtaBuildTestUtilsBundle()
|
||||
|
||||
options := mtaBuildOptions{ApplicationName: "myApp"}
|
||||
@ -88,16 +127,21 @@ func TestMtaBuild(t *testing.T) {
|
||||
assert.NotNil(t, err)
|
||||
|
||||
assert.Equal(t, "package.json file does not exist", err.Error())
|
||||
|
||||
})
|
||||
|
||||
t.Run("Write yaml file", func(t *testing.T) {
|
||||
|
||||
utilsMock := newMtaBuildTestUtilsBundle()
|
||||
|
||||
options := mtaBuildOptions{ApplicationName: "myApp", Platform: "CF", MtarName: "myName", Source: "./", Target: "./", EnableSetTimestamp: true}
|
||||
options := mtaBuildOptions{
|
||||
ApplicationName: "myApp",
|
||||
Platform: "CF",
|
||||
MtarName: "myName",
|
||||
Source: "./",
|
||||
Target: "./",
|
||||
EnableSetTimestamp: true,
|
||||
}
|
||||
|
||||
utilsMock.AddFile("package.json", []byte("{\"name\": \"myName\", \"version\": \"1.2.3\"}"))
|
||||
utilsMock.AddFile("package.json", []byte(`{"name": "myName", "version": "1.2.3"}`))
|
||||
|
||||
err := runMtaBuild(options, &cpe, utilsMock)
|
||||
|
||||
@ -125,16 +169,14 @@ func TestMtaBuild(t *testing.T) {
|
||||
assert.Equal(t, "myApp", result.Modules[0].Name)
|
||||
assert.Regexp(t, "^1\\.2\\.3-[\\d]{14}$", result.Modules[0].Parameters["version"])
|
||||
assert.Equal(t, "myApp", result.Modules[0].Parameters["name"])
|
||||
|
||||
})
|
||||
|
||||
t.Run("Dont write mta yaml file when already present no timestamp placeholder", func(t *testing.T) {
|
||||
|
||||
utilsMock := newMtaBuildTestUtilsBundle()
|
||||
|
||||
options := mtaBuildOptions{ApplicationName: "myApp"}
|
||||
|
||||
utilsMock.AddFile("package.json", []byte("{\"name\": \"myName\", \"version\": \"1.2.3\"}"))
|
||||
utilsMock.AddFile("package.json", []byte(`{"name": "myName", "version": "1.2.3"}`))
|
||||
utilsMock.AddFile("mta.yaml", []byte("already there"))
|
||||
|
||||
_ = runMtaBuild(options, &cpe, utilsMock)
|
||||
@ -143,12 +185,14 @@ func TestMtaBuild(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Write mta yaml file when already present with timestamp placeholder", func(t *testing.T) {
|
||||
|
||||
utilsMock := newMtaBuildTestUtilsBundle()
|
||||
|
||||
options := mtaBuildOptions{ApplicationName: "myApp", EnableSetTimestamp: true}
|
||||
options := mtaBuildOptions{
|
||||
ApplicationName: "myApp",
|
||||
EnableSetTimestamp: true,
|
||||
}
|
||||
|
||||
utilsMock.AddFile("package.json", []byte("{\"name\": \"myName\", \"version\": \"1.2.3\"}"))
|
||||
utilsMock.AddFile("package.json", []byte(`{"name": "myName", "version": "1.2.3"}`))
|
||||
utilsMock.AddFile("mta.yaml", []byte("already there with-${timestamp}"))
|
||||
|
||||
_ = runMtaBuild(options, &cpe, utilsMock)
|
||||
@ -157,14 +201,13 @@ func TestMtaBuild(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Mta build mbt toolset", func(t *testing.T) {
|
||||
|
||||
utilsMock := newMtaBuildTestUtilsBundle()
|
||||
|
||||
cpe.mtarFilePath = ""
|
||||
|
||||
options := mtaBuildOptions{ApplicationName: "myApp", Platform: "CF", MtarName: "myName.mtar", Source: "./", Target: "./"}
|
||||
|
||||
utilsMock.AddFile("package.json", []byte("{\"name\": \"myName\", \"version\": \"1.2.3\"}"))
|
||||
utilsMock.AddFile("package.json", []byte(`{"name": "myName", "version": "1.2.3"}`))
|
||||
|
||||
err := runMtaBuild(options, &cpe, utilsMock)
|
||||
|
||||
@ -179,14 +222,19 @@ func TestMtaBuild(t *testing.T) {
|
||||
|
||||
t.Run("Source and target related tests", func(t *testing.T) {
|
||||
t.Run("Mta build mbt toolset with custom source and target paths", func(t *testing.T) {
|
||||
|
||||
utilsMock := newMtaBuildTestUtilsBundle()
|
||||
|
||||
cpe.mtarFilePath = ""
|
||||
|
||||
options := mtaBuildOptions{ApplicationName: "myApp", Platform: "CF", MtarName: "myName.mtar", Source: "mySourcePath/", Target: "myTargetPath/"}
|
||||
options := mtaBuildOptions{
|
||||
ApplicationName: "myApp",
|
||||
Platform: "CF",
|
||||
MtarName: "myName.mtar",
|
||||
Source: "mySourcePath/",
|
||||
Target: "myTargetPath/",
|
||||
}
|
||||
|
||||
utilsMock.AddFile("package.json", []byte("{\"name\": \"myName\", \"version\": \"1.2.3\"}"))
|
||||
utilsMock.AddFile("package.json", []byte(`{"name": "myName", "version": "1.2.3"}`))
|
||||
|
||||
err := runMtaBuild(options, &cpe, utilsMock)
|
||||
|
||||
@ -194,9 +242,11 @@ func TestMtaBuild(t *testing.T) {
|
||||
|
||||
if assert.Len(t, utilsMock.Calls, 1) {
|
||||
assert.Equal(t, "mbt", utilsMock.Calls[0].Exec)
|
||||
assert.Equal(t, []string{"build", "--mtar", "myName.mtar", "--platform", "CF",
|
||||
assert.Equal(t, []string{
|
||||
"build", "--mtar", "myName.mtar", "--platform", "CF",
|
||||
"--source", filepath.FromSlash("mySourcePath/"),
|
||||
"--target", filepath.Join(_ignoreError(os.Getwd()), filepath.FromSlash("mySourcePath/myTargetPath/"))},
|
||||
"--target", filepath.Join(_ignoreError(os.Getwd()), filepath.FromSlash("mySourcePath/myTargetPath/")),
|
||||
},
|
||||
utilsMock.Calls[0].Params)
|
||||
}
|
||||
assert.Equal(t, "mySourcePath/myTargetPath/myName.mtar", cpe.mtarFilePath)
|
||||
@ -206,14 +256,20 @@ func TestMtaBuild(t *testing.T) {
|
||||
|
||||
t.Run("M2Path related tests", func(t *testing.T) {
|
||||
t.Run("Mta build mbt toolset with m2Path", func(t *testing.T) {
|
||||
|
||||
utilsMock := newMtaBuildTestUtilsBundle()
|
||||
utilsMock.CurrentDir = "root_folder/workspace"
|
||||
cpe.mtarFilePath = ""
|
||||
|
||||
options := mtaBuildOptions{ApplicationName: "myApp", Platform: "CF", MtarName: "myName.mtar", Source: "./", Target: "./", M2Path: ".pipeline/local_repo"}
|
||||
options := mtaBuildOptions{
|
||||
ApplicationName: "myApp",
|
||||
Platform: "CF",
|
||||
MtarName: "myName.mtar",
|
||||
Source: "./",
|
||||
Target: "./",
|
||||
M2Path: ".pipeline/local_repo",
|
||||
}
|
||||
|
||||
utilsMock.AddFile("mta.yaml", []byte("ID: \"myNameFromMtar\""))
|
||||
utilsMock.AddFile("mta.yaml", []byte(`ID: "myNameFromMtar"`))
|
||||
|
||||
err := runMtaBuild(options, &cpe, utilsMock)
|
||||
|
||||
@ -223,13 +279,18 @@ func TestMtaBuild(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Settings file releatd tests", func(t *testing.T) {
|
||||
|
||||
t.Run("Copy global settings file", func(t *testing.T) {
|
||||
|
||||
utilsMock := newMtaBuildTestUtilsBundle()
|
||||
utilsMock.AddFile("mta.yaml", []byte("ID: \"myNameFromMtar\""))
|
||||
utilsMock.AddFile("mta.yaml", []byte(`ID: "myNameFromMtar"`))
|
||||
|
||||
options := mtaBuildOptions{ApplicationName: "myApp", GlobalSettingsFile: "/opt/maven/settings.xml", Platform: "CF", MtarName: "myName", Source: "./", Target: "./"}
|
||||
options := mtaBuildOptions{
|
||||
ApplicationName: "myApp",
|
||||
GlobalSettingsFile: "/opt/maven/settings.xml",
|
||||
Platform: "CF",
|
||||
MtarName: "myName",
|
||||
Source: "./",
|
||||
Target: "./",
|
||||
}
|
||||
|
||||
err := runMtaBuild(options, &cpe, utilsMock)
|
||||
|
||||
@ -240,9 +301,8 @@ func TestMtaBuild(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("Copy project settings file", func(t *testing.T) {
|
||||
|
||||
utilsMock := newMtaBuildTestUtilsBundle()
|
||||
utilsMock.AddFile("mta.yaml", []byte("ID: \"myNameFromMtar\""))
|
||||
utilsMock.AddFile("mta.yaml", []byte(`ID: "myNameFromMtar"`))
|
||||
|
||||
options := mtaBuildOptions{ApplicationName: "myApp", ProjectSettingsFile: "/my/project/settings.xml", Platform: "CF", MtarName: "myName", Source: "./", Target: "./"}
|
||||
|
||||
@ -256,36 +316,102 @@ func TestMtaBuild(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("publish related tests", func(t *testing.T) {
|
||||
|
||||
t.Run("error when no repository url", func(t *testing.T) {
|
||||
|
||||
utilsMock := newMtaBuildTestUtilsBundle()
|
||||
utilsMock.AddFile("mta.yaml", []byte("ID: \"myNameFromMtar\""))
|
||||
utilsMock.AddFile("mta.yaml", []byte(`ID: "myNameFromMtar"`))
|
||||
|
||||
options := mtaBuildOptions{ApplicationName: "myApp", GlobalSettingsFile: "/opt/maven/settings.xml", Platform: "CF", MtarName: "myName", Source: "./", Target: "./", Publish: true}
|
||||
options := mtaBuildOptions{
|
||||
ApplicationName: "myApp",
|
||||
GlobalSettingsFile: "/opt/maven/settings.xml",
|
||||
Platform: "CF",
|
||||
MtarName: "myName",
|
||||
Source: "./",
|
||||
Target: "./",
|
||||
Publish: true,
|
||||
}
|
||||
|
||||
err := runMtaBuild(options, &cpe, utilsMock)
|
||||
|
||||
assert.Equal(t, "mtaDeploymentRepositoryUser, mtaDeploymentRepositoryPassword and mtaDeploymentRepositoryURL not found , must be present", err.Error())
|
||||
assert.Equal(t, "mtaDeploymentRepositoryUser, mtaDeploymentRepositoryPassword and mtaDeploymentRepositoryURL not found, must be present", err.Error())
|
||||
})
|
||||
|
||||
t.Run("error when no mtar group", func(t *testing.T) {
|
||||
|
||||
utilsMock := newMtaBuildTestUtilsBundle()
|
||||
utilsMock.AddFile("mta.yaml", []byte("ID: \"myNameFromMtar\""))
|
||||
utilsMock.AddFile("mta.yaml", []byte(`ID: "myNameFromMtar"`))
|
||||
|
||||
options := mtaBuildOptions{ApplicationName: "myApp", GlobalSettingsFile: "/opt/maven/settings.xml", Platform: "CF", MtarName: "myName", Source: "./", Target: "./", Publish: true,
|
||||
MtaDeploymentRepositoryURL: "dummy", MtaDeploymentRepositoryPassword: "dummy", MtaDeploymentRepositoryUser: "dummy"}
|
||||
options := mtaBuildOptions{
|
||||
ApplicationName: "myApp",
|
||||
GlobalSettingsFile: "/opt/maven/settings.xml",
|
||||
Platform: "CF",
|
||||
MtarName: "myName",
|
||||
Source: "./",
|
||||
Target: "./",
|
||||
Publish: true,
|
||||
MtaDeploymentRepositoryURL: "dummy",
|
||||
MtaDeploymentRepositoryPassword: "dummy",
|
||||
MtaDeploymentRepositoryUser: "dummy",
|
||||
}
|
||||
|
||||
err := runMtaBuild(options, &cpe, utilsMock)
|
||||
|
||||
assert.Equal(t, "mtarGroup, version not found and must be present", err.Error())
|
||||
})
|
||||
|
||||
t.Run("successful publish", func(t *testing.T) {
|
||||
utilsMock := newMtaBuildTestUtilsBundle()
|
||||
utilsMock.sendRequestReturns = func() (*http.Response, error) {
|
||||
return &http.Response{StatusCode: 200}, nil
|
||||
}
|
||||
utilsMock.AddFile("mta.yaml", []byte(`ID: "myNameFromMtar"`))
|
||||
utilsMock.openReturns = `{"version":"1.2.3"}`
|
||||
options := mtaBuildOptions{
|
||||
ApplicationName: "myApp",
|
||||
GlobalSettingsFile: "/opt/maven/settings.xml",
|
||||
Platform: "CF",
|
||||
MtarName: "test",
|
||||
Source: "./",
|
||||
Target: "./",
|
||||
Publish: true,
|
||||
MtaDeploymentRepositoryURL: "dummy",
|
||||
MtaDeploymentRepositoryPassword: "dummy",
|
||||
MtaDeploymentRepositoryUser: "dummy",
|
||||
MtarGroup: "dummy",
|
||||
Version: "dummy",
|
||||
}
|
||||
err := runMtaBuild(options, &cpe, utilsMock)
|
||||
assert.Nil(t, err)
|
||||
})
|
||||
|
||||
t.Run("succesful build artifact", func(t *testing.T) {
|
||||
utilsMock := newMtaBuildTestUtilsBundle()
|
||||
utilsMock.AddFile("mta.yaml", []byte(`ID: "myNameFromMtar"`))
|
||||
utilsMock.openReturns = `{"version":"1.2.3"}`
|
||||
utilsMock.sendRequestReturns = func() (*http.Response, error) {
|
||||
return &http.Response{StatusCode: 200}, nil
|
||||
}
|
||||
options := mtaBuildOptions{
|
||||
ApplicationName: "myApp",
|
||||
GlobalSettingsFile: "/opt/maven/settings.xml",
|
||||
Platform: "CF",
|
||||
MtarName: "test",
|
||||
Source: "./",
|
||||
Target: "./",
|
||||
Publish: true,
|
||||
MtaDeploymentRepositoryURL: "dummy",
|
||||
MtaDeploymentRepositoryPassword: "dummy",
|
||||
MtaDeploymentRepositoryUser: "dummy",
|
||||
MtarGroup: "dummy",
|
||||
Version: "dummy",
|
||||
CreateBuildArtifactsMetadata: true,
|
||||
}
|
||||
err := runMtaBuild(options, &cpe, utilsMock)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, cpe.custom.mtaBuildArtifacts, `{"Coordinates":[{"groupId":"dummy","artifactId":"test","version":"dummy","packaging":"mtar","buildPath":"./","url":"dummydummy/test/dummy/test-dummy.mtar","purl":""}]}`)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestMtaBuildSourceDir(t *testing.T) {
|
||||
|
||||
cpe := mtaBuildCommonPipelineEnvironment{}
|
||||
t.Run("getSourcePath", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
@ -338,7 +464,7 @@ func TestMtaBuildSourceDir(t *testing.T) {
|
||||
t.Run("create mta.yaml from config.source", func(t *testing.T) {
|
||||
utilsMock := newMtaBuildTestUtilsBundle()
|
||||
|
||||
utilsMock.AddFile("package.json", []byte("{\"name\": \"myName\", \"version\": \"1.2.3\"}"))
|
||||
utilsMock.AddFile("package.json", []byte(`{"name": "myName", "version": "1.2.3"}`))
|
||||
|
||||
_ = runMtaBuild(mtaBuildOptions{ApplicationName: "myApp", Source: "create"}, &cpe, utilsMock)
|
||||
|
||||
@ -359,35 +485,33 @@ func TestMtaBuildSourceDir(t *testing.T) {
|
||||
utilsMock := newMtaBuildTestUtilsBundle()
|
||||
|
||||
options := mtaBuildOptions{ApplicationName: "myApp", Platform: "CF", DefaultNpmRegistry: "https://example.org/npm", MtarName: "myName", Source: "./", Target: "./", CreateBOM: true}
|
||||
utilsMock.AddFile("package.json", []byte("{\"name\": \"myName\", \"version\": \"1.2.3\"}"))
|
||||
utilsMock.AddFile("package.json", []byte(`{"name": "myName", "version": "1.2.3"}`))
|
||||
|
||||
err := runMtaBuild(options, &cpe, utilsMock)
|
||||
assert.Nil(t, err)
|
||||
assert.Contains(t, utilsMock.Calls[0].Params, "--sbom-file-path")
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestMtaBuildMtar(t *testing.T) {
|
||||
|
||||
t.Run("getMtarName", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("mtar name from yaml", func(t *testing.T) {
|
||||
utilsMock := newMtaBuildTestUtilsBundle()
|
||||
utilsMock.AddFile("mta.yaml", []byte("ID: \"nameFromMtar\""))
|
||||
utilsMock.AddFile("mta.yaml", []byte(`ID: "nameFromMtar"`))
|
||||
|
||||
assert.Equal(t, filepath.FromSlash("nameFromMtar.mtar"), _ignoreErrorForGetMtarName(getMtarName(mtaBuildOptions{MtarName: ""}, "mta.yaml", utilsMock)))
|
||||
})
|
||||
t.Run("mtar name from yaml with suffixed value", func(t *testing.T) {
|
||||
utilsMock := newMtaBuildTestUtilsBundle()
|
||||
utilsMock.AddFile("mta.yaml", []byte("ID: \"nameFromMtar.mtar\""))
|
||||
utilsMock.AddFile("mta.yaml", []byte(`ID: "nameFromMtar.mtar"`))
|
||||
|
||||
assert.Equal(t, filepath.FromSlash("nameFromMtar.mtar"), _ignoreErrorForGetMtarName(getMtarName(mtaBuildOptions{MtarName: ""}, "mta.yaml", utilsMock)))
|
||||
})
|
||||
t.Run("mtar name from config", func(t *testing.T) {
|
||||
utilsMock := newMtaBuildTestUtilsBundle()
|
||||
utilsMock.AddFile("mta.yaml", []byte("ID: \"nameFromMtar\""))
|
||||
utilsMock.AddFile("mta.yaml", []byte(`ID: "nameFromMtar"`))
|
||||
|
||||
assert.Equal(t, filepath.FromSlash("nameFromConfig.mtar"), _ignoreErrorForGetMtarName(getMtarName(mtaBuildOptions{MtarName: "nameFromConfig.mtar"}, "mta.yaml", utilsMock)))
|
||||
})
|
||||
@ -412,7 +536,6 @@ func TestMtaBuildMtar(t *testing.T) {
|
||||
assert.Equal(t, filepath.FromSlash("source/target/mta.mtar"), getMtarFilePath(mtaBuildOptions{Source: "source", Target: "target"}, "mta.mtar"))
|
||||
})
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func _ignoreError(s string, e error) string {
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
"github.com/SAP/jenkins-library/pkg/piperutils"
|
||||
CredentialUtils "github.com/SAP/jenkins-library/pkg/piperutils"
|
||||
"github.com/SAP/jenkins-library/pkg/versioning"
|
||||
)
|
||||
@ -217,7 +218,7 @@ func (exec *Execute) publish(packageJSON, registry, username, password string, p
|
||||
coordinate.BuildPath = filepath.Dir(packageJSON)
|
||||
coordinate.URL = registry
|
||||
coordinate.Packaging = "tgz"
|
||||
coordinate.PURL = getPurl(packageJSON)
|
||||
coordinate.PURL = piperutils.GetPurl(filepath.Join(filepath.Dir(packageJSON), npmBomFilename))
|
||||
|
||||
*buildCoordinates = append(*buildCoordinates, coordinate)
|
||||
}
|
||||
@ -226,21 +227,6 @@ func (exec *Execute) publish(packageJSON, registry, username, password string, p
|
||||
return nil
|
||||
}
|
||||
|
||||
func getPurl(packageJSON string) string {
|
||||
expectedBomFilePath := filepath.Join(filepath.Dir(packageJSON) + "/" + npmBomFilename)
|
||||
exists, _ := CredentialUtils.FileExists(expectedBomFilePath)
|
||||
if !exists {
|
||||
log.Entry().Debugf("bom file doesn't exist and hence no pURL info: %v", expectedBomFilePath)
|
||||
return ""
|
||||
}
|
||||
bom, err := CredentialUtils.GetBom(expectedBomFilePath)
|
||||
if err != nil {
|
||||
log.Entry().Warnf("unable to get bom metdata : %v", err)
|
||||
return ""
|
||||
}
|
||||
return bom.Metadata.Component.Purl
|
||||
}
|
||||
|
||||
func (exec *Execute) readPackageScope(packageJSON string) (string, error) {
|
||||
b, err := exec.Utils.FileRead(packageJSON)
|
||||
if err != nil {
|
||||
|
@ -4,15 +4,15 @@
|
||||
package npm
|
||||
|
||||
import (
|
||||
"github.com/SAP/jenkins-library/pkg/mock"
|
||||
"io"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/SAP/jenkins-library/pkg/mock"
|
||||
|
||||
"github.com/SAP/jenkins-library/pkg/piperutils"
|
||||
"github.com/SAP/jenkins-library/pkg/versioning"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"os"
|
||||
)
|
||||
|
||||
type npmMockUtilsBundleRelativeGlob struct {
|
||||
@ -531,7 +531,7 @@ func TestNpmPublish(t *testing.T) {
|
||||
|
||||
// This stub simulates the behavior of npm pack and puts a tgz into the requested
|
||||
utils.execRunner.Stub = func(call string, stdoutReturn map[string]string, shouldFailOnCommand map[string]error, stdout io.Writer) error {
|
||||
//tgzTargetPath := filepath.Dir(test.packageDescriptors[0])
|
||||
// tgzTargetPath := filepath.Dir(test.packageDescriptors[0])
|
||||
utils.AddFile(filepath.Join(".", "package.tgz"), []byte("this is a tgz file"))
|
||||
return nil
|
||||
}
|
||||
@ -574,46 +574,3 @@ func TestNpmPublish(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func createTempFile(t *testing.T, dir string, filename string, content string) string {
|
||||
filePath := filepath.Join(dir, filename)
|
||||
err := os.WriteFile(filePath, []byte(content), 0666)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp file: %s", err)
|
||||
}
|
||||
return filePath
|
||||
}
|
||||
|
||||
func TestGetPurl(t *testing.T) {
|
||||
t.Run("valid BOM file", func(t *testing.T) {
|
||||
tempDir, err := piperutils.Files{}.TempDir("", "test")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp directory: %s", err)
|
||||
}
|
||||
|
||||
bomContent := `<bom>
|
||||
<metadata>
|
||||
<component>
|
||||
<purl>pkg:npm/com.example/mycomponent@1.0.0</purl>
|
||||
</component>
|
||||
<properties>
|
||||
<property name="name1" value="value1" />
|
||||
</properties>
|
||||
</metadata>
|
||||
</bom>`
|
||||
packageJsonFilePath := createTempFile(t, tempDir, "package.json", "")
|
||||
bomFilePath := createTempFile(t, tempDir, npmBomFilename, bomContent)
|
||||
defer os.Remove(bomFilePath)
|
||||
|
||||
purl := getPurl(packageJsonFilePath)
|
||||
assert.Equal(t, "pkg:npm/com.example/mycomponent@1.0.0", purl)
|
||||
})
|
||||
|
||||
t.Run("BOM file does not exist", func(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
packageJsonFilePath := createTempFile(t, tempDir, "pom.xml", "") // Create a temp pom file
|
||||
|
||||
purl := getPurl(packageJsonFilePath)
|
||||
assert.Equal(t, "", purl)
|
||||
})
|
||||
}
|
||||
|
@ -2,9 +2,10 @@ package piperutils
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/SAP/jenkins-library/pkg/log"
|
||||
)
|
||||
|
||||
// To serialize the cyclonedx BOM file
|
||||
@ -46,3 +47,12 @@ func GetBom(absoluteBomPath string) (Bom, error) {
|
||||
}
|
||||
return bom, nil
|
||||
}
|
||||
|
||||
func GetPurl(bomFilePath string) string {
|
||||
bom, err := GetBom(bomFilePath)
|
||||
if err != nil {
|
||||
log.Entry().Warnf("unable to get bom metadata: %v", err)
|
||||
return ""
|
||||
}
|
||||
return bom.Metadata.Component.Purl
|
||||
}
|
||||
|
@ -18,6 +18,18 @@ func createTempFile(t *testing.T, content string) (string, func()) {
|
||||
}
|
||||
}
|
||||
|
||||
const validBom = `<bom>
|
||||
<metadata>
|
||||
<component>
|
||||
<purl>pkg:maven/com.example/mycomponent@1.0.0</purl>
|
||||
</component>
|
||||
<properties>
|
||||
<property name="name1" value="value1" />
|
||||
<property name="name2" value="value2" />
|
||||
</properties>
|
||||
</metadata>
|
||||
</bom>`
|
||||
|
||||
func TestGetBom(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
@ -27,18 +39,8 @@ func TestGetBom(t *testing.T) {
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
name: "valid file",
|
||||
xmlContent: `<bom>
|
||||
<metadata>
|
||||
<component>
|
||||
<purl>pkg:maven/com.example/mycomponent@1.0.0</purl>
|
||||
</component>
|
||||
<properties>
|
||||
<property name="name1" value="value1" />
|
||||
<property name="name2" value="value2" />
|
||||
</properties>
|
||||
</metadata>
|
||||
</bom>`,
|
||||
name: "valid file",
|
||||
xmlContent: validBom,
|
||||
expectedBom: Bom{
|
||||
Metadata: Metadata{
|
||||
Component: BomComponent{
|
||||
@ -73,12 +75,8 @@ func TestGetBom(t *testing.T) {
|
||||
var fileName string
|
||||
var cleanup func()
|
||||
if tt.xmlContent != "" {
|
||||
var err error
|
||||
fileName, cleanup = createTempFile(t, tt.xmlContent)
|
||||
defer cleanup()
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp file: %s", err)
|
||||
}
|
||||
} else {
|
||||
// Use a non-existent file path
|
||||
fileName = "nonexistent.xml"
|
||||
@ -102,6 +100,57 @@ func TestGetBom(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetPurl(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
filePath string
|
||||
bomFilename string
|
||||
xmlContent string
|
||||
expectedPurl string
|
||||
expectError bool
|
||||
expectedError string
|
||||
}{
|
||||
{
|
||||
name: "valid BOM file",
|
||||
xmlContent: validBom,
|
||||
expectedPurl: "pkg:maven/com.example/mycomponent@1.0.0",
|
||||
},
|
||||
{
|
||||
name: "BOM file not found",
|
||||
xmlContent: "",
|
||||
expectedPurl: "",
|
||||
expectError: true,
|
||||
expectedError: "no such file or directory",
|
||||
},
|
||||
{
|
||||
name: "invalid BOM file",
|
||||
xmlContent: "<bom><metadata><component><purl>invalid xml</metadata></bom>",
|
||||
expectedPurl: "",
|
||||
expectError: true,
|
||||
expectedError: "XML syntax error",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
var filePath string
|
||||
var cleanup func()
|
||||
if tt.xmlContent != "" {
|
||||
filePath, cleanup = createTempFile(t, tt.xmlContent)
|
||||
defer cleanup()
|
||||
} else {
|
||||
// Use a non-existent file path
|
||||
filePath = "nonexistent.xml"
|
||||
}
|
||||
|
||||
purl := GetPurl(filePath)
|
||||
if purl != tt.expectedPurl {
|
||||
t.Errorf("Expected PURL: %v, got: %v", tt.expectedPurl, purl)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func bomEquals(a, b Bom) bool {
|
||||
// compare a and b manually since reflect.DeepEqual can be problematic with slices and nil values
|
||||
return a.Metadata.Component.Purl == b.Metadata.Component.Purl &&
|
||||
|
@ -244,6 +244,14 @@ spec:
|
||||
- STAGES
|
||||
- PARAMETERS
|
||||
default: true
|
||||
- name: createBuildArtifactsMetadata
|
||||
type: bool
|
||||
default: false
|
||||
description: metadata about the artifacts that are build and published, this metadata is generally used by steps downstream in the pipeline
|
||||
scope:
|
||||
- STEPS
|
||||
- STAGES
|
||||
- PARAMETERS
|
||||
outputs:
|
||||
resources:
|
||||
- name: commonPipelineEnvironment
|
||||
@ -253,6 +261,7 @@ spec:
|
||||
- name: custom/mtaBuildToolDesc
|
||||
- name: custom/mtarPublishedUrl
|
||||
- name: custom/buildSettingsInfo
|
||||
- name: custom/mtaBuildArtifacts
|
||||
- name: reports
|
||||
type: reports
|
||||
params:
|
||||
|
Loading…
Reference in New Issue
Block a user