You've already forked sap-jenkins-library
							
							
				mirror of
				https://github.com/SAP/jenkins-library.git
				synced 2025-10-30 23:57:50 +02:00 
			
		
		
		
	abapEnvironment automatically building the next package (#4148)
* api user scatch * cv, pv +steps * dust wipe * escape odata values in filter * use correct validation url * headers * add missing error check * restrict to non revertable packages * Correct dotted-version-string calculation + tests
This commit is contained in:
		| @@ -1,10 +1,6 @@ | ||||
| package cmd | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"net/url" | ||||
|  | ||||
| 	"github.com/SAP/jenkins-library/pkg/abap/aakaas" | ||||
| 	abapbuild "github.com/SAP/jenkins-library/pkg/abap/build" | ||||
| 	"github.com/SAP/jenkins-library/pkg/abaputils" | ||||
| @@ -21,6 +17,11 @@ func abapAddonAssemblyKitCheckCVs(config abapAddonAssemblyKitCheckCVsOptions, te | ||||
| } | ||||
|  | ||||
| func runAbapAddonAssemblyKitCheckCVs(config *abapAddonAssemblyKitCheckCVsOptions, telemetryData *telemetry.CustomData, utils *aakaas.AakUtils, cpe *abapAddonAssemblyKitCheckCVsCommonPipelineEnvironment) error { | ||||
|  | ||||
| 	log.Entry().Info("╔══════════════════════════════╗") | ||||
| 	log.Entry().Info("║ abapAddonAssemblyKitCheckCVs ║") | ||||
| 	log.Entry().Info("╚══════════════════════════════╝") | ||||
|  | ||||
| 	conn := new(abapbuild.Connector) | ||||
| 	if err := conn.InitAAKaaS(config.AbapAddonAssemblyKitEndpoint, config.Username, config.Password, *utils); err != nil { | ||||
| 		return err | ||||
| @@ -32,14 +33,22 @@ func runAbapAddonAssemblyKitCheckCVs(config *abapAddonAssemblyKitCheckCVsOptions | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	for i := range addonDescriptor.Repositories { | ||||
| 		var c componentVersion | ||||
| 		c.initCV(addonDescriptor.Repositories[i], *conn) | ||||
| 		err := c.validate() | ||||
| 		if err != nil { | ||||
| 	for i, repo := range addonDescriptor.Repositories { | ||||
| 		componentVersion := new(aakaas.ComponentVersion) | ||||
| 		if err := componentVersion.ConstructComponentVersion(addonDescriptor.Repositories[i], *conn); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		c.copyFieldsToRepo(&addonDescriptor.Repositories[i]) | ||||
| 		if err := componentVersion.Validate(); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		componentVersion.CopyVersionFieldsToRepo(&addonDescriptor.Repositories[i]) | ||||
|  | ||||
| 		log.Entry().Infof("Using cCTS %t", repo.UseClassicCTS) | ||||
| 		log.Entry().Infof("CommitId %s", repo.CommitID) | ||||
|  | ||||
| 		if !repo.UseClassicCTS && repo.CommitID == "" { | ||||
| 			return errors.Errorf("CommitID missing in repo '%s' of the addon.yml", repo.Name) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// now Software Component Versions fields are valid, but maybe Product Version was checked before, so copy that part from CPE | ||||
| @@ -63,57 +72,3 @@ func combineYAMLRepositoriesWithCPEProduct(addonDescriptor abaputils.AddonDescri | ||||
| 	addonDescriptorFromCPE.Repositories = addonDescriptor.Repositories | ||||
| 	return addonDescriptorFromCPE | ||||
| } | ||||
|  | ||||
| func (c *componentVersion) initCV(repo abaputils.Repository, conn abapbuild.Connector) { | ||||
| 	c.Connector = conn | ||||
| 	c.Name = repo.Name | ||||
| 	c.VersionYAML = repo.VersionYAML | ||||
| 	c.CommitID = repo.CommitID | ||||
| 	c.UseClassicCTS = repo.UseClassicCTS | ||||
| } | ||||
|  | ||||
| func (c *componentVersion) copyFieldsToRepo(initialRepo *abaputils.Repository) { | ||||
| 	initialRepo.Version = c.Version | ||||
| 	initialRepo.SpLevel = c.SpLevel | ||||
| 	initialRepo.PatchLevel = c.PatchLevel | ||||
| } | ||||
|  | ||||
| func (c *componentVersion) validate() error { | ||||
| 	log.Entry().Infof("Validate component %s version %s and resolve version", c.Name, c.VersionYAML) | ||||
| 	appendum := "/odata/aas_ocs_package/ValidateComponentVersion?Name='" + url.QueryEscape(c.Name) + "'&Version='" + url.QueryEscape(c.VersionYAML) + "'" | ||||
| 	body, err := c.Connector.Get(appendum) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	var jCV jsonComponentVersion | ||||
| 	if err := json.Unmarshal(body, &jCV); err != nil { | ||||
| 		return errors.Wrap(err, "Unexpected AAKaaS response for Validate Component Version: "+string(body)) | ||||
| 	} | ||||
| 	c.Name = jCV.ComponentVersion.Name | ||||
| 	c.Version = jCV.ComponentVersion.Version | ||||
| 	c.SpLevel = jCV.ComponentVersion.SpLevel | ||||
| 	c.PatchLevel = jCV.ComponentVersion.PatchLevel | ||||
| 	log.Entry().Infof("Resolved version %s, splevel %s, patchlevel %s", c.Version, c.SpLevel, c.PatchLevel) | ||||
| 	log.Entry().Infof("Using cCTS %t", c.UseClassicCTS) | ||||
|  | ||||
| 	if !c.UseClassicCTS && c.CommitID == "" { | ||||
| 		return fmt.Errorf("CommitID missing in repo '%s' of the addon.yml", c.Name) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| type jsonComponentVersion struct { | ||||
| 	ComponentVersion *componentVersion `json:"d"` | ||||
| } | ||||
|  | ||||
| type componentVersion struct { | ||||
| 	abapbuild.Connector | ||||
| 	Name          string `json:"Name"` | ||||
| 	VersionYAML   string | ||||
| 	Version       string `json:"Version"` | ||||
| 	SpLevel       string `json:"SpLevel"` | ||||
| 	PatchLevel    string `json:"PatchLevel"` | ||||
| 	UseClassicCTS bool | ||||
| 	CommitID      string | ||||
| } | ||||
|   | ||||
| @@ -5,9 +5,7 @@ import ( | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/SAP/jenkins-library/pkg/abap/aakaas" | ||||
| 	abapbuild "github.com/SAP/jenkins-library/pkg/abap/build" | ||||
| 	"github.com/SAP/jenkins-library/pkg/abaputils" | ||||
| 	"github.com/pkg/errors" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| @@ -15,7 +13,7 @@ func TestCheckCVsStep(t *testing.T) { | ||||
| 	var config abapAddonAssemblyKitCheckCVsOptions | ||||
| 	var cpe abapAddonAssemblyKitCheckCVsCommonPipelineEnvironment | ||||
| 	bundle := aakaas.NewAakBundleMock() | ||||
| 	bundle.SetBody(responseCheckCVs) | ||||
| 	bundle.SetBody(aakaas.ResponseCheckCVs) | ||||
| 	utils := bundle.GetUtils() | ||||
| 	config.Username = "dummyUser" | ||||
| 	config.Password = "dummyPassword" | ||||
| @@ -52,78 +50,6 @@ func TestCheckCVsStep(t *testing.T) { | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestInitCV(t *testing.T) { | ||||
| 	t.Run("test init", func(t *testing.T) { | ||||
| 		conn := new(abapbuild.Connector) | ||||
| 		conn.Client = &abaputils.ClientMock{} | ||||
| 		repo := abaputils.Repository{ | ||||
| 			Name:        "/DRNMSPC/COMP01", | ||||
| 			VersionYAML: "1.2.3", | ||||
| 		} | ||||
| 		var c componentVersion | ||||
| 		c.initCV(repo, *conn) | ||||
| 		assert.Equal(t, "/DRNMSPC/COMP01", c.Name) | ||||
| 		assert.Equal(t, "1.2.3", c.VersionYAML) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestValidateCV(t *testing.T) { | ||||
| 	conn := new(abapbuild.Connector) | ||||
| 	t.Run("test validate - success", func(t *testing.T) { | ||||
| 		conn.Client = &abaputils.ClientMock{ | ||||
| 			Body: responseCheckCVs, | ||||
| 		} | ||||
| 		c := componentVersion{ | ||||
| 			Connector:   *conn, | ||||
| 			Name:        "/DRNMSPC/COMP01", | ||||
| 			VersionYAML: "1.2.3", | ||||
| 			CommitID:    "HUGO1234", | ||||
| 		} | ||||
| 		conn.Client = &abaputils.ClientMock{ | ||||
| 			Body: responseCheckCVs, | ||||
| 		} | ||||
| 		err := c.validate() | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, "0001", c.Version) | ||||
| 		assert.Equal(t, "0002", c.SpLevel) | ||||
| 		assert.Equal(t, "0003", c.PatchLevel) | ||||
| 	}) | ||||
| 	t.Run("test validate - with error", func(t *testing.T) { | ||||
| 		conn.Client = &abaputils.ClientMock{ | ||||
| 			Body:  "ErrorBody", | ||||
| 			Error: errors.New("Validation failed"), | ||||
| 		} | ||||
| 		c := componentVersion{ | ||||
| 			Connector:   *conn, | ||||
| 			Name:        "/DRNMSPC/COMP01", | ||||
| 			VersionYAML: "1.2.3", | ||||
| 			CommitID:    "HUGO1234", | ||||
| 		} | ||||
| 		err := c.validate() | ||||
| 		assert.Error(t, err) | ||||
| 		assert.Equal(t, "", c.Version) | ||||
| 		assert.Equal(t, "", c.SpLevel) | ||||
| 		assert.Equal(t, "", c.PatchLevel) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestCopyFieldsCV(t *testing.T) { | ||||
| 	t.Run("test copyFieldsToRepo", func(t *testing.T) { | ||||
| 		repo := abaputils.Repository{ | ||||
| 			Name:        "/DRNMSPC/COMP01", | ||||
| 			VersionYAML: "1.2.3", | ||||
| 		} | ||||
| 		var c componentVersion | ||||
| 		c.Version = "0001" | ||||
| 		c.SpLevel = "0002" | ||||
| 		c.PatchLevel = "0003" | ||||
| 		c.copyFieldsToRepo(&repo) | ||||
| 		assert.Equal(t, "0001", repo.Version) | ||||
| 		assert.Equal(t, "0002", repo.SpLevel) | ||||
| 		assert.Equal(t, "0003", repo.PatchLevel) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestCombineYAMLRepositoriesWithCPEProduct(t *testing.T) { | ||||
| 	t.Run("test combineYAMLRepositoriesWithCPEProduct", func(t *testing.T) { | ||||
| 		addonDescriptor := abaputils.AddonDescriptor{ | ||||
| @@ -151,19 +77,3 @@ func TestCombineYAMLRepositoriesWithCPEProduct(t *testing.T) { | ||||
| 		assert.Equal(t, "3.2.1", finalAddonDescriptor.Repositories[1].VersionYAML) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| var responseCheckCVs = `{ | ||||
|     "d": { | ||||
|         "__metadata": { | ||||
|             "id": "https://W7Q.DMZWDF.SAP.CORP:443/odata/aas_ocs_package/SoftwareComponentVersionSet(Name='%2FDRNMSPC%2FCOMP01',Version='0001')", | ||||
|             "uri": "https://W7Q.DMZWDF.SAP.CORP:443/odata/aas_ocs_package/SoftwareComponentVersionSet(Name='%2FDRNMSPC%2FCOMP01',Version='0001')", | ||||
|             "type": "SSDA.AAS_ODATA_PACKAGE_SRV.SoftwareComponentVersion" | ||||
|         }, | ||||
|         "Name": "/DRNMSPC/COMP01", | ||||
|         "Version": "0001", | ||||
|         "SpLevel": "0002", | ||||
|         "PatchLevel": "0003", | ||||
|         "Vendor": "", | ||||
|         "VendorType": "" | ||||
|     } | ||||
| }` | ||||
|   | ||||
| @@ -1,16 +1,12 @@ | ||||
| package cmd | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"net/url" | ||||
|  | ||||
| 	"github.com/SAP/jenkins-library/pkg/abap/aakaas" | ||||
| 	abapbuild "github.com/SAP/jenkins-library/pkg/abap/build" | ||||
| 	"github.com/SAP/jenkins-library/pkg/abaputils" | ||||
| 	"github.com/SAP/jenkins-library/pkg/log" | ||||
| 	"github.com/SAP/jenkins-library/pkg/piperutils" | ||||
| 	"github.com/SAP/jenkins-library/pkg/telemetry" | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
|  | ||||
| func abapAddonAssemblyKitCheckPV(config abapAddonAssemblyKitCheckPVOptions, telemetryData *telemetry.CustomData, cpe *abapAddonAssemblyKitCheckPVCommonPipelineEnvironment) { | ||||
| @@ -22,6 +18,10 @@ func abapAddonAssemblyKitCheckPV(config abapAddonAssemblyKitCheckPVOptions, tele | ||||
| } | ||||
| func runAbapAddonAssemblyKitCheckPV(config *abapAddonAssemblyKitCheckPVOptions, telemetryData *telemetry.CustomData, utils aakaas.AakUtils, cpe *abapAddonAssemblyKitCheckPVCommonPipelineEnvironment) error { | ||||
|  | ||||
| 	log.Entry().Info("╔═════════════════════════════╗") | ||||
| 	log.Entry().Info("║ abapAddonAssemblyKitCheckPV ║") | ||||
| 	log.Entry().Info("╚═════════════════════════════╝") | ||||
|  | ||||
| 	conn := new(abapbuild.Connector) | ||||
| 	if err := conn.InitAAKaaS(config.AbapAddonAssemblyKitEndpoint, config.Username, config.Password, utils); err != nil { | ||||
| 		return err | ||||
| @@ -33,12 +33,14 @@ func runAbapAddonAssemblyKitCheckPV(config *abapAddonAssemblyKitCheckPVOptions, | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	pv := new(productVersion).init(addonDescriptor, *conn) | ||||
| 	err = pv.validateAndResolveVersionFields() | ||||
| 	if err != nil { | ||||
| 	pv := new(aakaas.ProductVersion) | ||||
| 	if err := pv.ConstructProductversion(addonDescriptor, *conn); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	pv.transferVersionFields(&addonDescriptor) | ||||
| 	if err = pv.ValidateAndResolveVersionFields(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	pv.CopyVersionFieldsToDescriptor(&addonDescriptor) | ||||
|  | ||||
| 	// now Product Version fields are valid, but maybe Component Versions (Repositories) were checked before, so copy that part from CPE | ||||
| 	// we don't care for errors | ||||
| @@ -64,50 +66,3 @@ func runAbapAddonAssemblyKitCheckPV(config *abapAddonAssemblyKitCheckPVOptions, | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (p *productVersion) init(desc abaputils.AddonDescriptor, conn abapbuild.Connector) *productVersion { | ||||
| 	p.Connector = conn | ||||
| 	p.Name = desc.AddonProduct | ||||
| 	p.VersionYAML = desc.AddonVersionYAML | ||||
|  | ||||
| 	return p | ||||
| } | ||||
|  | ||||
| func (p *productVersion) transferVersionFields(initialAddonDescriptor *abaputils.AddonDescriptor) { | ||||
| 	initialAddonDescriptor.AddonVersion = p.Version | ||||
| 	initialAddonDescriptor.AddonSpsLevel = p.SpsLevel | ||||
| 	initialAddonDescriptor.AddonPatchLevel = p.PatchLevel | ||||
| } | ||||
|  | ||||
| func (p *productVersion) validateAndResolveVersionFields() error { | ||||
| 	log.Entry().Infof("Validate product '%s' version '%s' and resolve version", p.Name, p.VersionYAML) | ||||
| 	appendum := "/odata/aas_ocs_package/ValidateProductVersion?Name='" + url.QueryEscape(p.Name) + "'&Version='" + url.QueryEscape(p.VersionYAML) + "'" | ||||
| 	body, err := p.Connector.Get(appendum) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	var jPV jsonProductVersion | ||||
| 	if err := json.Unmarshal(body, &jPV); err != nil { | ||||
| 		return errors.Wrap(err, "Unexpected AAKaaS response for Validate Product Version: "+string(body)) | ||||
| 	} | ||||
| 	p.Name = jPV.ProductVersion.Name | ||||
| 	p.Version = jPV.ProductVersion.Version | ||||
| 	p.SpsLevel = jPV.ProductVersion.SpsLevel | ||||
| 	p.PatchLevel = jPV.ProductVersion.PatchLevel | ||||
| 	log.Entry().Infof("Resolved version %s, spslevel %s, patchlevel %s", p.Version, p.SpsLevel, p.PatchLevel) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| type jsonProductVersion struct { | ||||
| 	ProductVersion *productVersion `json:"d"` | ||||
| } | ||||
|  | ||||
| type productVersion struct { | ||||
| 	abapbuild.Connector | ||||
| 	Name           string `json:"Name"` | ||||
| 	VersionYAML    string | ||||
| 	Version        string `json:"Version"` | ||||
| 	SpsLevel       string `json:"SpsLevel"` | ||||
| 	PatchLevel     string `json:"PatchLevel"` | ||||
| 	TargetVectorID string | ||||
| } | ||||
|   | ||||
| @@ -5,9 +5,7 @@ import ( | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/SAP/jenkins-library/pkg/abap/aakaas" | ||||
| 	abapbuild "github.com/SAP/jenkins-library/pkg/abap/build" | ||||
| 	"github.com/SAP/jenkins-library/pkg/abaputils" | ||||
| 	"github.com/pkg/errors" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| @@ -15,7 +13,7 @@ func TestCheckPVStep(t *testing.T) { | ||||
| 	var config abapAddonAssemblyKitCheckPVOptions | ||||
| 	var cpe abapAddonAssemblyKitCheckPVCommonPipelineEnvironment | ||||
| 	bundle := aakaas.NewAakBundleMock() | ||||
| 	bundle.SetBody(responseCheckPV) | ||||
| 	bundle.SetBody(aakaas.ResponseCheckPV) | ||||
| 	utils := bundle.GetUtils() | ||||
| 	config.Username = "dummyUser" | ||||
| 	config.Password = "dummyPassword" | ||||
| @@ -44,87 +42,3 @@ func TestCheckPVStep(t *testing.T) { | ||||
| 		assert.Error(t, err, "Did expect error") | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestInitPV(t *testing.T) { | ||||
| 	t.Run("test init", func(t *testing.T) { | ||||
| 		conn := new(abapbuild.Connector) | ||||
| 		conn.Client = &abaputils.ClientMock{} | ||||
| 		prodvers := abaputils.AddonDescriptor{ | ||||
| 			AddonProduct:     "/DRNMSPC/PRD01", | ||||
| 			AddonVersionYAML: "3.2.1", | ||||
| 		} | ||||
|  | ||||
| 		var pv productVersion | ||||
| 		pv.init(prodvers, *conn) | ||||
| 		assert.Equal(t, "/DRNMSPC/PRD01", pv.Name) | ||||
| 		assert.Equal(t, "3.2.1", pv.VersionYAML) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestValidatePV(t *testing.T) { | ||||
| 	conn := new(abapbuild.Connector) | ||||
| 	t.Run("test validate - success", func(t *testing.T) { | ||||
| 		conn.Client = &abaputils.ClientMock{ | ||||
| 			Body: responseCheckPV, | ||||
| 		} | ||||
| 		pv := productVersion{ | ||||
| 			Connector:   *conn, | ||||
| 			Name:        "/DRNMSPC/PRD01", | ||||
| 			VersionYAML: "3.2.1", | ||||
| 		} | ||||
| 		err := pv.validateAndResolveVersionFields() | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, "0003", pv.Version) | ||||
| 		assert.Equal(t, "0002", pv.SpsLevel) | ||||
| 		assert.Equal(t, "0001", pv.PatchLevel) | ||||
| 	}) | ||||
| 	t.Run("test validate - with error", func(t *testing.T) { | ||||
| 		conn.Client = &abaputils.ClientMock{ | ||||
| 			Body:  "ErrorBody", | ||||
| 			Error: errors.New("Validation failed"), | ||||
| 		} | ||||
| 		pv := productVersion{ | ||||
| 			Connector:   *conn, | ||||
| 			Name:        "/DRNMSPC/PRD01", | ||||
| 			VersionYAML: "3.2.1", | ||||
| 		} | ||||
| 		err := pv.validateAndResolveVersionFields() | ||||
| 		assert.Error(t, err) | ||||
| 		assert.Equal(t, "", pv.Version) | ||||
| 		assert.Equal(t, "", pv.SpsLevel) | ||||
| 		assert.Equal(t, "", pv.PatchLevel) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestCopyFieldsPV(t *testing.T) { | ||||
| 	t.Run("test copyFieldsToRepo", func(t *testing.T) { | ||||
| 		prodVers := abaputils.AddonDescriptor{ | ||||
| 			AddonProduct:     "/DRNMSPC/PRD01", | ||||
| 			AddonVersionYAML: "1.2.3", | ||||
| 		} | ||||
| 		var pv productVersion | ||||
| 		pv.Version = "0003" | ||||
| 		pv.SpsLevel = "0002" | ||||
| 		pv.PatchLevel = "0001" | ||||
| 		pv.transferVersionFields(&prodVers) | ||||
| 		assert.Equal(t, "0003", prodVers.AddonVersion) | ||||
| 		assert.Equal(t, "0002", prodVers.AddonSpsLevel) | ||||
| 		assert.Equal(t, "0001", prodVers.AddonPatchLevel) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| var responseCheckPV = `{ | ||||
|     "d": { | ||||
|         "__metadata": { | ||||
|             "id": "https://W7Q.DMZWDF.SAP.CORP:443/odata/aas_ocs_package/ProductVersionSet(Name='%2FDRNMSPC%2FPRD01',Version='0001')", | ||||
|             "uri": "https://W7Q.DMZWDF.SAP.CORP:443/odata/aas_ocs_package/ProductVersionSet(Name='%2FDRNMSPC%2FPRD01',Version='0001')", | ||||
|             "type": "SSDA.AAS_ODATA_PACKAGE_SRV.ProductVersion" | ||||
|         }, | ||||
|         "Name": "/DRNMSPC/PRD01", | ||||
|         "Version": "0003", | ||||
|         "SpsLevel": "0002", | ||||
|         "PatchLevel": "0001", | ||||
|         "Vendor": "", | ||||
|         "VendorType": "" | ||||
|     } | ||||
| }` | ||||
|   | ||||
							
								
								
									
										69
									
								
								pkg/abap/aakaas/componentVersion.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								pkg/abap/aakaas/componentVersion.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | ||||
| package aakaas | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"net/url" | ||||
|  | ||||
| 	abapbuild "github.com/SAP/jenkins-library/pkg/abap/build" | ||||
| 	"github.com/SAP/jenkins-library/pkg/abaputils" | ||||
| 	"github.com/SAP/jenkins-library/pkg/log" | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
|  | ||||
| const cvQueryURL string = "/odata/aas_ocs_package/xSSDAxC_Component_Version" | ||||
| const cvValidateURL string = "/odata/aas_ocs_package/ValidateComponentVersion" | ||||
|  | ||||
| type ComponentVersion struct { | ||||
| 	versionable | ||||
| } | ||||
|  | ||||
| func (c *ComponentVersion) ConstructComponentVersion(repo abaputils.Repository, conn abapbuild.Connector) error { | ||||
| 	if err := c.constructVersionable(repo.Name, repo.VersionYAML, conn, pvQueryURL); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if err := c.resolveNext(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (c *ComponentVersion) CopyVersionFieldsToRepo(repo *abaputils.Repository) { | ||||
| 	repo.Version = c.TechRelease | ||||
| 	repo.SpLevel = c.TechSpLevel | ||||
| 	repo.PatchLevel = c.TechPatchLevel | ||||
| } | ||||
|  | ||||
| func (c *ComponentVersion) Validate() error { | ||||
| 	log.Entry().Infof("Validate component %s version %s and resolve version", c.Name, c.Version) | ||||
|  | ||||
| 	values := url.Values{} | ||||
| 	values.Set("Name", "'"+c.Name+"'") | ||||
| 	values.Set("Version", "'"+c.Version+"'") | ||||
| 	requestUrl := cvValidateURL + "?" + values.Encode() | ||||
|  | ||||
| 	body, err := c.connector.Get(requestUrl) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	var response jsonComponentVersionValidationResponse | ||||
| 	if err := json.Unmarshal(body, &response); err != nil { | ||||
| 		return errors.Wrap(err, "Unexpected AAKaaS response for Validate Component Version: "+string(body)) | ||||
| 	} | ||||
| 	c.Name = response.Wrapper.Name | ||||
| 	c.TechRelease = response.Wrapper.TechRelease | ||||
| 	c.TechSpLevel = response.Wrapper.TechSpLevel | ||||
| 	c.TechPatchLevel = response.Wrapper.TechPatchLevel | ||||
| 	log.Entry().Infof("Resolved version %s, splevel %s, patchlevel %s", c.TechRelease, c.TechSpLevel, c.TechPatchLevel) | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| type jsonComponentVersionValidationResponse struct { | ||||
| 	Wrapper struct { | ||||
| 		Name           string `json:"Name"` | ||||
| 		TechRelease    string `json:"Version"` | ||||
| 		TechSpLevel    string `json:"SpLevel"` | ||||
| 		TechPatchLevel string `json:"PatchLevel"` | ||||
| 	} `json:"d"` | ||||
| } | ||||
							
								
								
									
										64
									
								
								pkg/abap/aakaas/componentVersion_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								pkg/abap/aakaas/componentVersion_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | ||||
| package aakaas | ||||
|  | ||||
| import ( | ||||
| 	"testing" | ||||
|  | ||||
| 	abapbuild "github.com/SAP/jenkins-library/pkg/abap/build" | ||||
| 	"github.com/SAP/jenkins-library/pkg/abaputils" | ||||
| 	"github.com/pkg/errors" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| func TestInitCV(t *testing.T) { | ||||
| 	conn := new(abapbuild.Connector) | ||||
| 	conn.Client = &abaputils.ClientMock{} | ||||
| 	repo := abaputils.Repository{ | ||||
| 		Name:        "/DRNMSPC/COMP01", | ||||
| 		VersionYAML: "1.2.3", | ||||
| 	} | ||||
| 	var c ComponentVersion | ||||
|  | ||||
| 	t.Run("test init", func(t *testing.T) { | ||||
| 		c.ConstructComponentVersion(repo, *conn) | ||||
| 		assert.Equal(t, "/DRNMSPC/COMP01", c.Name) | ||||
| 		assert.Equal(t, "1.2.3", c.Version) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("test validate - success", func(t *testing.T) { | ||||
| 		conn.Client = &abaputils.ClientMock{ | ||||
| 			Body: ResponseCheckCVs, | ||||
| 		} | ||||
| 		c.ConstructComponentVersion(repo, *conn) | ||||
|  | ||||
| 		err := c.Validate() | ||||
|  | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, "0001", c.TechRelease) | ||||
| 		assert.Equal(t, "0002", c.TechSpLevel) | ||||
| 		assert.Equal(t, "0003", c.TechPatchLevel) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("test validate - with error", func(t *testing.T) { | ||||
| 		conn.Client = &abaputils.ClientMock{ | ||||
| 			Body:  "ErrorBody", | ||||
| 			Error: errors.New("Validation failed"), | ||||
| 		} | ||||
| 		c.ConstructComponentVersion(repo, *conn) | ||||
|  | ||||
| 		err := c.Validate() | ||||
|  | ||||
| 		assert.Error(t, err) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("test copyFieldsToRepo", func(t *testing.T) { | ||||
|  | ||||
| 		var c ComponentVersion | ||||
| 		c.TechRelease = "0001" | ||||
| 		c.TechSpLevel = "0002" | ||||
| 		c.TechPatchLevel = "0003" | ||||
| 		c.CopyVersionFieldsToRepo(&repo) | ||||
| 		assert.Equal(t, "0001", repo.Version) | ||||
| 		assert.Equal(t, "0002", repo.SpLevel) | ||||
| 		assert.Equal(t, "0003", repo.PatchLevel) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										67
									
								
								pkg/abap/aakaas/productVersion.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								pkg/abap/aakaas/productVersion.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,67 @@ | ||||
| package aakaas | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"net/url" | ||||
|  | ||||
| 	abapbuild "github.com/SAP/jenkins-library/pkg/abap/build" | ||||
| 	"github.com/SAP/jenkins-library/pkg/abaputils" | ||||
| 	"github.com/SAP/jenkins-library/pkg/log" | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
|  | ||||
| const pvQueryURL string = "/odata/aas_ocs_package/xSSDAxC_Product_Version" | ||||
| const pvValidateURL string = "/odata/aas_ocs_package/ValidateProductVersion" | ||||
|  | ||||
| type ProductVersion struct { | ||||
| 	versionable | ||||
| } | ||||
|  | ||||
| func (p *ProductVersion) ConstructProductversion(desc abaputils.AddonDescriptor, conn abapbuild.Connector) error { | ||||
| 	if err := p.constructVersionable(desc.AddonProduct, desc.AddonVersionYAML, conn, pvQueryURL); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if err := p.resolveNext(); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (p *ProductVersion) CopyVersionFieldsToDescriptor(desc *abaputils.AddonDescriptor) { | ||||
| 	desc.AddonVersion = p.TechRelease | ||||
| 	desc.AddonSpsLevel = p.TechSpLevel | ||||
| 	desc.AddonPatchLevel = p.TechPatchLevel | ||||
| } | ||||
|  | ||||
| func (p *ProductVersion) ValidateAndResolveVersionFields() error { | ||||
| 	log.Entry().Infof("Validate product '%s' version '%s' and resolve version", p.Name, p.Version) | ||||
|  | ||||
| 	values := url.Values{} | ||||
| 	values.Set("Name", "'"+p.Name+"'") | ||||
| 	values.Set("Version", "'"+p.Version+"'") | ||||
| 	requestUrl := pvValidateURL + "?" + values.Encode() | ||||
|  | ||||
| 	body, err := p.connector.Get(requestUrl) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	var response jsonProductVersionValidationResponse | ||||
| 	if err := json.Unmarshal(body, &response); err != nil { | ||||
| 		return errors.Wrap(err, "Unexpected AAKaaS response for Validate Product Version: "+string(body)) | ||||
| 	} | ||||
| 	p.Name = response.Wrapper.Name | ||||
| 	p.TechRelease = response.Wrapper.TechRelease | ||||
| 	p.TechSpLevel = response.Wrapper.TechSpLevel | ||||
| 	p.TechPatchLevel = response.Wrapper.TechPatchLevel | ||||
| 	log.Entry().Infof("Resolved version %s, spslevel %s, patchlevel %s", p.TechRelease, p.TechSpLevel, p.TechPatchLevel) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| type jsonProductVersionValidationResponse struct { | ||||
| 	Wrapper struct { | ||||
| 		Name           string `json:"Name"` | ||||
| 		TechRelease    string `json:"Version"` | ||||
| 		TechSpLevel    string `json:"SpsLevel"` | ||||
| 		TechPatchLevel string `json:"PatchLevel"` | ||||
| 	} `json:"d"` | ||||
| } | ||||
							
								
								
									
										58
									
								
								pkg/abap/aakaas/productVersion_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								pkg/abap/aakaas/productVersion_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | ||||
| package aakaas | ||||
|  | ||||
| import ( | ||||
| 	"testing" | ||||
|  | ||||
| 	abapbuild "github.com/SAP/jenkins-library/pkg/abap/build" | ||||
| 	"github.com/SAP/jenkins-library/pkg/abaputils" | ||||
| 	"github.com/pkg/errors" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| func TestInitPV(t *testing.T) { | ||||
| 	conn := new(abapbuild.Connector) | ||||
| 	conn.Client = &abaputils.ClientMock{} | ||||
| 	prodVers := abaputils.AddonDescriptor{ | ||||
| 		AddonProduct:     "/DRNMSPC/PRD01", | ||||
| 		AddonVersionYAML: "3.2.1", | ||||
| 	} | ||||
| 	var pv ProductVersion | ||||
|  | ||||
| 	t.Run("test init", func(t *testing.T) { | ||||
| 		pv.ConstructProductversion(prodVers, *conn) | ||||
| 		assert.Equal(t, "/DRNMSPC/PRD01", pv.Name) | ||||
| 		assert.Equal(t, "3.2.1", pv.Version) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("test validate - success", func(t *testing.T) { | ||||
| 		conn.Client = &abaputils.ClientMock{ | ||||
| 			Body: ResponseCheckPV, | ||||
| 		} | ||||
| 		pv.ConstructProductversion(prodVers, *conn) | ||||
| 		err := pv.ValidateAndResolveVersionFields() | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, "0003", pv.TechRelease) | ||||
| 		assert.Equal(t, "0002", pv.TechSpLevel) | ||||
| 		assert.Equal(t, "0001", pv.TechPatchLevel) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("test validate - with error", func(t *testing.T) { | ||||
| 		conn.Client = &abaputils.ClientMock{ | ||||
| 			Body:  "ErrorBody", | ||||
| 			Error: errors.New("Validation failed"), | ||||
| 		} | ||||
| 		pv.ConstructProductversion(prodVers, *conn) | ||||
| 		err := pv.ValidateAndResolveVersionFields() | ||||
| 		assert.Error(t, err) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("test copyFieldsToRepo", func(t *testing.T) { | ||||
| 		pv.TechRelease = "0003" | ||||
| 		pv.TechSpLevel = "0002" | ||||
| 		pv.TechPatchLevel = "0001" | ||||
| 		pv.CopyVersionFieldsToDescriptor(&prodVers) | ||||
| 		assert.Equal(t, "0003", prodVers.AddonVersion) | ||||
| 		assert.Equal(t, "0002", prodVers.AddonSpsLevel) | ||||
| 		assert.Equal(t, "0001", prodVers.AddonPatchLevel) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										142
									
								
								pkg/abap/aakaas/testData.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								pkg/abap/aakaas/testData.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,142 @@ | ||||
| //go:build !release | ||||
| // +build !release | ||||
|  | ||||
| /* | ||||
| ** The Test Data is partly re-used by the steps in cmd folder, thus we Export them but remove the file from release build | ||||
|  */ | ||||
|  | ||||
| package aakaas | ||||
|  | ||||
| import abapbuild "github.com/SAP/jenkins-library/pkg/abap/build" | ||||
|  | ||||
| var ResponseCheckPV = `{ | ||||
|     "d": { | ||||
|         "Name": "/DRNMSPC/PRD01", | ||||
|         "Version": "0003", | ||||
|         "SpsLevel": "0002", | ||||
|         "PatchLevel": "0001", | ||||
|         "Vendor": "", | ||||
|         "VendorType": "" | ||||
|     } | ||||
| }` | ||||
|  | ||||
| var ResponseCheckCVs = `{ | ||||
|     "d": { | ||||
|         "Name": "/DRNMSPC/COMP01", | ||||
|         "Version": "0001", | ||||
|         "SpLevel": "0002", | ||||
|         "PatchLevel": "0003", | ||||
|         "Vendor": "", | ||||
|         "VendorType": "" | ||||
|     } | ||||
| }` | ||||
|  | ||||
| var emptyResultBody = `{ | ||||
|     "d": { | ||||
|         "results": [] | ||||
|     } | ||||
| }` | ||||
|  | ||||
| var testDataAakaasCVGetReleaseExisting = abapbuild.MockData{ | ||||
| 	Method: `GET`, | ||||
| 	Url:    `/odata/aas_ocs_package/xSSDAxC_Component_Version?%24filter=Name+eq+%27DummyComp%27+and+TechSpLevel+eq+%270000%27+and+TechPatchLevel+eq+%270000%27+and+%28+DeliveryStatus+eq+%27R%27+or+DeliveryStatus+eq+%27C%27+or+DeliveryStatus+eq+%27T%27+or+DeliveryStatus+eq+%27P%27+%29&%24format=json&%24orderby=TechRelease+desc&%24select=Name%2CVersion%2CTechRelease%2CTechSpLevel%2CTechPatchLevel&%24top=1`, | ||||
| 	Body: `{ | ||||
| 		"d": { | ||||
| 			"results": [ | ||||
| 				{ | ||||
| 					"Name": "DummyComp", | ||||
| 					"Version": "1.0.0", | ||||
| 					"TechRelease": "1", | ||||
| 					"TechSpLevel": "0000", | ||||
| 					"TechPatchLevel": "0000" | ||||
| 				} | ||||
| 			] | ||||
| 		} | ||||
| 	}`, | ||||
| 	StatusCode: 200, | ||||
| } | ||||
|  | ||||
| var testDataAakaasCVGetReleaseNonExisting = abapbuild.MockData{ | ||||
| 	Method:     `GET`, | ||||
| 	Url:        `/odata/aas_ocs_package/xSSDAxC_Component_Version?%24filter=Name+eq+%27DummyComp%27+and+TechSpLevel+eq+%270000%27+and+TechPatchLevel+eq+%270000%27+and+%28+DeliveryStatus+eq+%27R%27+or+DeliveryStatus+eq+%27C%27+or+DeliveryStatus+eq+%27T%27+or+DeliveryStatus+eq+%27P%27+%29&%24format=json&%24orderby=TechRelease+desc&%24select=Name%2CVersion%2CTechRelease%2CTechSpLevel%2CTechPatchLevel&%24top=1`, | ||||
| 	Body:       emptyResultBody, | ||||
| 	StatusCode: 200, | ||||
| } | ||||
|  | ||||
| var testDataAakaasCVGetSpLevelExisting = abapbuild.MockData{ | ||||
| 	Method: `GET`, | ||||
| 	Url:    `/odata/aas_ocs_package/xSSDAxC_Component_Version?%24filter=Name+eq+%27DummyComp%27+and+TechRelease+eq+%271%27+and+TechPatchLevel+eq+%270000%27++and+%28+DeliveryStatus+eq+%27R%27+or+DeliveryStatus+eq+%27C%27+or+DeliveryStatus+eq+%27T%27+or+DeliveryStatus+eq+%27P%27+%29&%24format=json&%24orderby=TechSpLevel+desc&%24select=Name%2CVersion%2CTechRelease%2CTechSpLevel%2CTechPatchLevel&%24top=1`, | ||||
| 	Body: `{ | ||||
| 		"d": { | ||||
| 			"results": [ | ||||
| 				{ | ||||
| 					"Name": "DummyComp", | ||||
| 					"Version": "1.7.0", | ||||
| 					"TechRelease": "1", | ||||
| 					"TechSpLevel": "0007", | ||||
| 					"TechPatchLevel": "0000" | ||||
| 				} | ||||
| 			] | ||||
| 		} | ||||
| 	}`, | ||||
| 	StatusCode: 200, | ||||
| } | ||||
|  | ||||
| var testDataAakaasCVGetSpLevelNonExisting = abapbuild.MockData{ | ||||
| 	Method:     `GET`, | ||||
| 	Url:        `/odata/aas_ocs_package/xSSDAxC_Component_Version?%24filter=Name+eq+%27DummyComp%27+and+TechRelease+eq+%271%27+and+TechPatchLevel+eq+%270000%27++and+%28+DeliveryStatus+eq+%27R%27+or+DeliveryStatus+eq+%27C%27+or+DeliveryStatus+eq+%27T%27+or+DeliveryStatus+eq+%27P%27+%29&%24format=json&%24orderby=TechSpLevel+desc&%24select=Name%2CVersion%2CTechRelease%2CTechSpLevel%2CTechPatchLevel&%24top=1`, | ||||
| 	Body:       emptyResultBody, | ||||
| 	StatusCode: 200, | ||||
| } | ||||
|  | ||||
| var testDataAakaasCVGetPatchLevelExisting = abapbuild.MockData{ | ||||
| 	Method: `GET`, | ||||
| 	Url:    `/odata/aas_ocs_package/xSSDAxC_Component_Version?%24filter=Name+eq+%27DummyComp%27+and+TechRelease+eq+%271%27+and+TechSpLevel+eq+%270003%27+and+%28+DeliveryStatus+eq+%27R%27+or+DeliveryStatus+eq+%27C%27+or+DeliveryStatus+eq+%27T%27+or+DeliveryStatus+eq+%27P%27+%29&%24format=json&%24orderby=TechPatchLevel+desc&%24select=Name%2CVersion%2CTechRelease%2CTechSpLevel%2CTechPatchLevel&%24top=1`, | ||||
| 	Body: `{ | ||||
| 		"d": { | ||||
| 			"results": [ | ||||
| 				{ | ||||
| 					"Name": "DummyComp", | ||||
| 					"Version": "1.3.46", | ||||
| 					"TechRelease": "1", | ||||
| 					"TechSpLevel": "0003", | ||||
| 					"TechPatchLevel": "0046" | ||||
| 				} | ||||
| 			] | ||||
| 		} | ||||
| 	}`, | ||||
| 	StatusCode: 200, | ||||
| } | ||||
|  | ||||
| var testDataAakaasCVGetPatchLevelNonExisting = abapbuild.MockData{ | ||||
| 	Method:     `GET`, | ||||
| 	Url:        `/odata/aas_ocs_package/xSSDAxC_Component_Version?%24filter=Name+eq+%27DummyComp%27+and+TechRelease+eq+%271%27+and+TechSpLevel+eq+%270003%27+and+%28+DeliveryStatus+eq+%27R%27+or+DeliveryStatus+eq+%27C%27+or+DeliveryStatus+eq+%27T%27+or+DeliveryStatus+eq+%27P%27+%29&%24format=json&%24orderby=TechPatchLevel+desc&%24select=Name%2CVersion%2CTechRelease%2CTechSpLevel%2CTechPatchLevel&%24top=1`, | ||||
| 	Body:       emptyResultBody, | ||||
| 	StatusCode: 200, | ||||
| } | ||||
|  | ||||
| var testDataAakaasPVGetReleaseExisting = abapbuild.MockData{ | ||||
| 	Method: `GET`, | ||||
| 	Url:    `/odata/aas_ocs_package/xSSDAxC_Product_Version?%24filter=Name+eq+%27DummyProd%27+and+TechSpLevel+eq+%270000%27+and+TechPatchLevel+eq+%270000%27+and+%28+DeliveryStatus+eq+%27R%27+or+DeliveryStatus+eq+%27C%27+or+DeliveryStatus+eq+%27T%27+or+DeliveryStatus+eq+%27P%27+%29&%24format=json&%24orderby=TechRelease+desc&%24select=Name%2CVersion%2CTechRelease%2CTechSpLevel%2CTechPatchLevel&%24top=1`, | ||||
| 	Body: `{ | ||||
|         "d": { | ||||
|             "results": [ | ||||
|                 { | ||||
|                     "Name": "DummyProd", | ||||
|                     "Version": "1.0.0", | ||||
|                     "TechRelease": "0001", | ||||
|                     "TechSpLevel": "0000", | ||||
|                     "TechPatchLevel": "0000" | ||||
|                 } | ||||
|             ] | ||||
|         } | ||||
|     }`, | ||||
| 	StatusCode: 200, | ||||
| } | ||||
|  | ||||
| var testDataAakaasPVGetReleaseNonExisting = abapbuild.MockData{ | ||||
| 	Method:     `GET`, | ||||
| 	Url:        `/odata/aas_ocs_package/xSSDAxC_Product_Version?%24filter=Name+eq+%27DummyProd%27+and+TechSpLevel+eq+%270000%27+and+TechPatchLevel+eq+%270000%27+and+%28+DeliveryStatus+eq+%27R%27+or+DeliveryStatus+eq+%27C%27+or+DeliveryStatus+eq+%27T%27+or+DeliveryStatus+eq+%27P%27+%29&%24format=json&%24orderby=TechRelease+desc&%24select=Name%2CVersion%2CTechRelease%2CTechSpLevel%2CTechPatchLevel&%24top=1`, | ||||
| 	Body:       emptyResultBody, | ||||
| 	StatusCode: 200, | ||||
| } | ||||
							
								
								
									
										177
									
								
								pkg/abap/aakaas/versionables.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								pkg/abap/aakaas/versionables.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,177 @@ | ||||
| package aakaas | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"net/url" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
|  | ||||
| 	abapbuild "github.com/SAP/jenkins-library/pkg/abap/build" | ||||
| 	"github.com/SAP/jenkins-library/pkg/log" | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
|  | ||||
| const wildCard string = "NEXT" | ||||
|  | ||||
| type versionable struct { | ||||
| 	Name           string | ||||
| 	Version        string | ||||
| 	TechRelease    string | ||||
| 	TechSpLevel    string | ||||
| 	TechPatchLevel string | ||||
|  | ||||
| 	connector abapbuild.Connector | ||||
| 	queryUrl  string | ||||
| } | ||||
|  | ||||
| type versionables struct { | ||||
| 	Wrapper struct { | ||||
| 		Vs []versionable `json:"results"` | ||||
| 	} `json:"d"` | ||||
| } | ||||
|  | ||||
| func (v *versionable) constructVersionable(name string, dottedVersionString string, connector abapbuild.Connector, queryURL string) error { | ||||
| 	if name == "" { | ||||
| 		return errors.New("No Component/Product Name provided") | ||||
| 	} | ||||
| 	subStrings := strings.Split(dottedVersionString, ".") | ||||
| 	if len(subStrings) != 3 { | ||||
| 		return errors.New("Provide a dotted-version-string with 2 '.' [Release.SP.Patch]") | ||||
| 	} | ||||
| 	v.Name = name | ||||
| 	v.TechRelease = subStrings[0] | ||||
| 	v.TechSpLevel = fmt.Sprintf("%04s", subStrings[1]) | ||||
| 	v.TechPatchLevel = fmt.Sprintf("%04s", subStrings[2]) | ||||
| 	v.connector = connector | ||||
| 	v.queryUrl = queryURL | ||||
| 	v.Version = dottedVersionString | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (v *versionable) resolveNext() error { | ||||
|  | ||||
| 	switch strings.Count(v.Version, wildCard) { | ||||
| 	case 0: | ||||
| 		return nil | ||||
| 	case 1: | ||||
| 		log.Entry().Info("Wildcard detected in dotted-version-string. Looking up highest existing package in AAKaaS...") | ||||
| 		var err error | ||||
| 		switch wildCard { | ||||
| 		case v.TechRelease: | ||||
| 			err = v.resolveRelease() | ||||
| 		case v.TechSpLevel: | ||||
| 			err = v.resolveSpLevel() | ||||
| 		case v.TechPatchLevel: | ||||
| 			err = v.resolvePatchLevel() | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		if v.Version, err = v.getDottedVersionString(); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	default: | ||||
| 		return errors.New("The dotted-version-string must contain only one wildcard " + wildCard) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (v *versionable) resolveRelease() error { | ||||
| 	//take only unrevertable status R/C for packages and T/P for TargetVectors | ||||
| 	filter := "Name eq '" + v.Name + "' and TechSpLevel eq '0000' and TechPatchLevel eq '0000' and ( DeliveryStatus eq 'R' or DeliveryStatus eq 'C' or DeliveryStatus eq 'T' or DeliveryStatus eq 'P' )" | ||||
| 	orderBy := "TechRelease desc" | ||||
|  | ||||
| 	if queryResuult, err := v.queryVersion(filter, orderBy); err != nil { | ||||
| 		return err | ||||
| 	} else { | ||||
| 		if newRelease, err := strconv.Atoi(queryResuult.TechRelease); err != nil { | ||||
| 			return err | ||||
| 		} else { | ||||
| 			v.TechRelease = strconv.Itoa(newRelease + 1) | ||||
| 			return nil | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (v *versionable) resolveSpLevel() error { | ||||
| 	filter := "Name eq '" + v.Name + "' and TechRelease eq '" + v.TechRelease + "' and TechPatchLevel eq '0000'  and ( DeliveryStatus eq 'R' or DeliveryStatus eq 'C' or DeliveryStatus eq 'T' or DeliveryStatus eq 'P' )" | ||||
| 	orderBy := "TechSpLevel desc" | ||||
|  | ||||
| 	if queryResuult, err := v.queryVersion(filter, orderBy); err != nil { | ||||
| 		return err | ||||
| 	} else { | ||||
| 		if newSpLevel, err := strconv.Atoi(queryResuult.TechSpLevel); err != nil { | ||||
| 			return err | ||||
| 		} else { | ||||
| 			v.TechSpLevel = fmt.Sprintf("%04d", newSpLevel+1) | ||||
| 			return nil | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (v *versionable) resolvePatchLevel() error { | ||||
| 	filter := "Name eq '" + v.Name + "' and TechRelease eq '" + v.TechRelease + "' and TechSpLevel eq '" + v.TechSpLevel + "' and ( DeliveryStatus eq 'R' or DeliveryStatus eq 'C' or DeliveryStatus eq 'T' or DeliveryStatus eq 'P' )" | ||||
| 	orderBy := "TechPatchLevel desc" | ||||
|  | ||||
| 	if queryResuult, err := v.queryVersion(filter, orderBy); err != nil { | ||||
| 		return err | ||||
| 	} else { | ||||
| 		if newPatchLevel, err := strconv.Atoi(queryResuult.TechPatchLevel); err != nil { | ||||
| 			return err | ||||
| 		} else { | ||||
| 			v.TechPatchLevel = fmt.Sprintf("%04d", newPatchLevel+1) | ||||
| 			return nil | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (v *versionable) queryVersion(filter string, orderBy string) (*versionable, error) { | ||||
| 	result := versionable{} | ||||
|  | ||||
| 	values := url.Values{} | ||||
| 	values.Set("$filter", filter) | ||||
| 	values.Set("$orderby", orderBy) | ||||
| 	values.Set("$select", "Name,Version,TechRelease,TechSpLevel,TechPatchLevel") | ||||
| 	values.Set("$format", "json") | ||||
| 	values.Set("$top", "1") | ||||
|  | ||||
| 	requestUrl := v.queryUrl + "?" + values.Encode() | ||||
|  | ||||
| 	if body, err := v.connector.Get(requestUrl); err != nil { | ||||
| 		return &result, err | ||||
| 	} else { | ||||
| 		Versions := versionables{} | ||||
| 		if err := json.Unmarshal(body, &Versions); err != nil { | ||||
| 			return &result, errors.Wrap(err, "Unexpected AAKaaS response for Component Version Query: "+string(body)) | ||||
| 		} | ||||
| 		switch len(Versions.Wrapper.Vs) { | ||||
| 		case 0: | ||||
| 			result = versionable{ | ||||
| 				TechRelease:    "0", | ||||
| 				TechSpLevel:    "0000", | ||||
| 				TechPatchLevel: "0000", | ||||
| 			} | ||||
| 		case 1: | ||||
| 			result = Versions.Wrapper.Vs[0] | ||||
| 		default: | ||||
| 			return &result, errors.New("Unexpected Number of CVs in result: " + fmt.Sprint(len(Versions.Wrapper.Vs))) | ||||
| 		} | ||||
| 	} | ||||
| 	return &result, nil | ||||
| } | ||||
|  | ||||
| func (v *versionable) getDottedVersionString() (string, error) { | ||||
| 	var spLevelAsnumber int | ||||
| 	var patchLevelAsNumber int | ||||
| 	var err error | ||||
| 	if spLevelAsnumber, err = strconv.Atoi(v.TechSpLevel); err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	if patchLevelAsNumber, err = strconv.Atoi(v.TechPatchLevel); err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	dottedVersionString := strings.Join([]string{v.TechRelease, strconv.Itoa(spLevelAsnumber), strconv.Itoa(patchLevelAsNumber)}, ".") | ||||
| 	return dottedVersionString, nil | ||||
| } | ||||
							
								
								
									
										131
									
								
								pkg/abap/aakaas/versionables_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								pkg/abap/aakaas/versionables_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,131 @@ | ||||
| package aakaas | ||||
|  | ||||
| import ( | ||||
| 	"testing" | ||||
|  | ||||
| 	abapbuild "github.com/SAP/jenkins-library/pkg/abap/build" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| func TestCvResolve(t *testing.T) { | ||||
| 	//arrange | ||||
| 	conn := new(abapbuild.Connector) | ||||
| 	mc := abapbuild.NewMockClient() | ||||
| 	conn.Client = &mc | ||||
| 	vers := versionable{} | ||||
|  | ||||
| 	t.Run("Factory Success", func(t *testing.T) { | ||||
| 		//act | ||||
| 		err := vers.constructVersionable("DummyComp", "1.2.3", *conn, "") | ||||
| 		//assert | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, "DummyComp", vers.Name) | ||||
| 		assert.Equal(t, "1", vers.TechRelease) | ||||
| 		assert.Equal(t, "0002", vers.TechSpLevel) | ||||
| 		assert.Equal(t, "0003", vers.TechPatchLevel) | ||||
| 		assert.Equal(t, "1.2.3", vers.Version) | ||||
| 	}) | ||||
| 	t.Run("Factory No Name", func(t *testing.T) { | ||||
| 		err := vers.constructVersionable("", "1.2.3", *conn, "") | ||||
| 		assert.Error(t, err) | ||||
| 	}) | ||||
| 	t.Run("Factory Version too long", func(t *testing.T) { | ||||
| 		err := vers.constructVersionable("DummyComp", "1.0.0.0", *conn, "") | ||||
| 		assert.Error(t, err) | ||||
| 	}) | ||||
| 	t.Run("Factory Version too short", func(t *testing.T) { | ||||
|  | ||||
| 		err := vers.constructVersionable("DummyComp", "1.0", *conn, "") | ||||
| 		assert.Error(t, err) | ||||
| 	}) | ||||
| 	t.Run("ComponentVersion NEXT Release Existing", func(t *testing.T) { | ||||
| 		mc.AddData(testDataAakaasCVGetReleaseExisting) | ||||
| 		err := vers.constructVersionable("DummyComp", wildCard+".0.0", *conn, cvQueryURL) | ||||
| 		assert.NoError(t, err) | ||||
| 		err = vers.resolveNext() | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, "2", vers.TechRelease) | ||||
| 		assert.Equal(t, "0000", vers.TechSpLevel) | ||||
| 		assert.Equal(t, "0000", vers.TechPatchLevel) | ||||
| 		assert.Equal(t, "2.0.0", vers.Version) | ||||
| 	}) | ||||
| 	t.Run("ComponentVersion NEXT Release Non Existing", func(t *testing.T) { | ||||
| 		mc.AddData(testDataAakaasCVGetReleaseNonExisting) | ||||
| 		err := vers.constructVersionable("DummyComp", wildCard+".0.0", *conn, cvQueryURL) | ||||
| 		assert.NoError(t, err) | ||||
| 		err = vers.resolveNext() | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, "1", vers.TechRelease) | ||||
| 		assert.Equal(t, "0000", vers.TechSpLevel) | ||||
| 		assert.Equal(t, "0000", vers.TechPatchLevel) | ||||
| 		assert.Equal(t, "1.0.0", vers.Version) | ||||
| 	}) | ||||
| 	t.Run("ComponentVersion NEXT SP Level Existing", func(t *testing.T) { | ||||
| 		mc.AddData(testDataAakaasCVGetSpLevelExisting) | ||||
| 		err := vers.constructVersionable("DummyComp", "1."+wildCard+".0", *conn, cvQueryURL) | ||||
| 		assert.NoError(t, err) | ||||
| 		err = vers.resolveNext() | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, "1", vers.TechRelease) | ||||
| 		assert.Equal(t, "0008", vers.TechSpLevel) | ||||
| 		assert.Equal(t, "0000", vers.TechPatchLevel) | ||||
| 		assert.Equal(t, "1.8.0", vers.Version) | ||||
| 	}) | ||||
| 	t.Run("ComponentVersion NEXT SP Level Non Existing", func(t *testing.T) { | ||||
| 		//This one should lead to an error later on as AOI is needed - anyway we can't just produce a differen package then customized... | ||||
| 		mc.AddData(testDataAakaasCVGetSpLevelNonExisting) | ||||
| 		err := vers.constructVersionable("DummyComp", "1."+wildCard+".0", *conn, cvQueryURL) | ||||
| 		assert.NoError(t, err) | ||||
| 		err = vers.resolveNext() | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, "1", vers.TechRelease) | ||||
| 		assert.Equal(t, "0001", vers.TechSpLevel) | ||||
| 		assert.Equal(t, "0000", vers.TechPatchLevel) | ||||
| 		assert.Equal(t, "1.1.0", vers.Version) | ||||
| 	}) | ||||
| 	t.Run("ComponentVersion NEXT Patch Level Existing", func(t *testing.T) { | ||||
| 		mc.AddData(testDataAakaasCVGetPatchLevelExisting) | ||||
| 		err := vers.constructVersionable("DummyComp", "1.3."+wildCard, *conn, cvQueryURL) | ||||
| 		assert.NoError(t, err) | ||||
| 		err = vers.resolveNext() | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, "1", vers.TechRelease) | ||||
| 		assert.Equal(t, "0003", vers.TechSpLevel) | ||||
| 		assert.Equal(t, "0047", vers.TechPatchLevel) | ||||
| 		assert.Equal(t, "1.3.47", vers.Version) | ||||
| 	}) | ||||
| 	t.Run("ComponentVersion NEXT Patch Level Non Existing", func(t *testing.T) { | ||||
| 		//This one should lead to an error later on as AOI is needed - anyway we can't just produce a differen package then customized... | ||||
| 		mc.AddData(testDataAakaasCVGetPatchLevelNonExisting) | ||||
| 		err := vers.constructVersionable("DummyComp", "1.3."+wildCard, *conn, cvQueryURL) | ||||
| 		assert.NoError(t, err) | ||||
| 		err = vers.resolveNext() | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, "1", vers.TechRelease) | ||||
| 		assert.Equal(t, "0003", vers.TechSpLevel) | ||||
| 		assert.Equal(t, "0001", vers.TechPatchLevel) | ||||
| 		assert.Equal(t, "1.3.1", vers.Version) | ||||
| 	}) | ||||
| 	t.Run("Product Version NEXT Release Existing", func(t *testing.T) { | ||||
| 		mc.AddData(testDataAakaasPVGetReleaseExisting) | ||||
| 		err := vers.constructVersionable("DummyProd", wildCard+".0.0", *conn, pvQueryURL) | ||||
| 		assert.NoError(t, err) | ||||
| 		err = vers.resolveNext() | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, "2", vers.TechRelease) | ||||
| 		assert.Equal(t, "0000", vers.TechSpLevel) | ||||
| 		assert.Equal(t, "0000", vers.TechPatchLevel) | ||||
| 		assert.Equal(t, "2.0.0", vers.Version) | ||||
| 	}) | ||||
| 	t.Run("Product Version NEXT Release Non Existing", func(t *testing.T) { | ||||
| 		mc.AddData(testDataAakaasPVGetReleaseNonExisting) | ||||
| 		err := vers.constructVersionable("DummyProd", wildCard+".0.0", *conn, pvQueryURL) | ||||
| 		assert.NoError(t, err) | ||||
| 		err = vers.resolveNext() | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, "1", vers.TechRelease) | ||||
| 		assert.Equal(t, "0000", vers.TechSpLevel) | ||||
| 		assert.Equal(t, "0000", vers.TechPatchLevel) | ||||
| 		assert.Equal(t, "1.0.0", vers.Version) | ||||
| 	}) | ||||
| } | ||||
		Reference in New Issue
	
	Block a user