github.com/ouraigua/jenkins-library@v0.0.0-20231028010029-fbeaf2f3aa9b/pkg/abap/aakaas/versionables.go (about)

     1  package aakaas
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"net/url"
     7  	"strconv"
     8  	"strings"
     9  
    10  	abapbuild "github.com/SAP/jenkins-library/pkg/abap/build"
    11  	"github.com/SAP/jenkins-library/pkg/log"
    12  	"github.com/pkg/errors"
    13  )
    14  
    15  const wildCard string = "NEXT"
    16  const statusFilterCV string = "DeliveryStatus eq 'R'"
    17  const statusFilterPV string = "DeliveryStatus eq 'T' or DeliveryStatus eq 'P'"
    18  
    19  type versionable struct {
    20  	Name           string
    21  	Version        string
    22  	TechRelease    string
    23  	TechSpLevel    string
    24  	TechPatchLevel string
    25  
    26  	connector abapbuild.Connector
    27  	queryUrl  string
    28  }
    29  
    30  type versionables struct {
    31  	Wrapper struct {
    32  		Vs []versionable `json:"results"`
    33  	} `json:"d"`
    34  }
    35  
    36  func (v *versionable) constructVersionable(name string, dottedVersionString string, connector abapbuild.Connector, queryURL string) error {
    37  	if name == "" {
    38  		return errors.New("No Component/Product Name provided")
    39  	}
    40  	subStrings := strings.Split(dottedVersionString, ".")
    41  	if len(subStrings) != 3 {
    42  		return errors.New("Provide a dotted-version-string with 2 '.' [Release.SP.Patch]")
    43  	}
    44  	v.Name = name
    45  	v.TechRelease = subStrings[0]
    46  	v.TechSpLevel = fmt.Sprintf("%04s", subStrings[1])
    47  	v.TechPatchLevel = fmt.Sprintf("%04s", subStrings[2])
    48  	v.connector = connector
    49  	v.queryUrl = queryURL
    50  	v.Version = dottedVersionString
    51  	return nil
    52  }
    53  
    54  func (v *versionable) resolveNext(statusFilter string) error {
    55  
    56  	switch strings.Count(v.Version, wildCard) {
    57  	case 0:
    58  		return nil
    59  	case 1:
    60  		log.Entry().Info("Wildcard detected in dotted-version-string. Looking up highest existing package in AAKaaS...")
    61  		var err error
    62  		switch wildCard {
    63  		case v.TechRelease:
    64  			err = v.resolveRelease(statusFilter)
    65  		case v.TechSpLevel:
    66  			err = v.resolveSpLevel(statusFilter)
    67  		case v.TechPatchLevel:
    68  			err = v.resolvePatchLevel(statusFilter)
    69  		}
    70  		if err != nil {
    71  			return err
    72  		}
    73  		if v.Version, err = v.getDottedVersionString(); err != nil {
    74  			return err
    75  		}
    76  	default:
    77  		return errors.New("The dotted-version-string must contain only one wildcard " + wildCard)
    78  	}
    79  
    80  	return nil
    81  }
    82  
    83  func (v *versionable) resolveRelease(statusFilter string) error {
    84  	filter := "Name eq '" + v.Name + "' and TechSpLevel eq '0000' and TechPatchLevel eq '0000' and ( " + statusFilter + " )"
    85  	orderBy := "TechRelease desc"
    86  
    87  	if queryResuult, err := v.queryVersion(filter, orderBy); err != nil {
    88  		return err
    89  	} else {
    90  		if newRelease, err := strconv.Atoi(queryResuult.TechRelease); err != nil {
    91  			return err
    92  		} else {
    93  			v.TechRelease = strconv.Itoa(newRelease + 1)
    94  			return nil
    95  		}
    96  	}
    97  }
    98  
    99  func (v *versionable) resolveSpLevel(statusFilter string) error {
   100  	filter := "Name eq '" + v.Name + "' and TechRelease eq '" + v.TechRelease + "' and TechPatchLevel eq '0000'  and ( " + statusFilter + " )"
   101  	orderBy := "TechSpLevel desc"
   102  
   103  	if queryResuult, err := v.queryVersion(filter, orderBy); err != nil {
   104  		return err
   105  	} else {
   106  		if newSpLevel, err := strconv.Atoi(queryResuult.TechSpLevel); err != nil {
   107  			return err
   108  		} else {
   109  			v.TechSpLevel = fmt.Sprintf("%04d", newSpLevel+1)
   110  			return nil
   111  		}
   112  	}
   113  }
   114  
   115  func (v *versionable) resolvePatchLevel(statusFilter string) error {
   116  	filter := "Name eq '" + v.Name + "' and TechRelease eq '" + v.TechRelease + "' and TechSpLevel eq '" + v.TechSpLevel + "' and ( " + statusFilter + " )"
   117  	orderBy := "TechPatchLevel desc"
   118  
   119  	if queryResuult, err := v.queryVersion(filter, orderBy); err != nil {
   120  		return err
   121  	} else {
   122  		if newPatchLevel, err := strconv.Atoi(queryResuult.TechPatchLevel); err != nil {
   123  			return err
   124  		} else {
   125  			v.TechPatchLevel = fmt.Sprintf("%04d", newPatchLevel+1)
   126  			return nil
   127  		}
   128  	}
   129  }
   130  
   131  func (v *versionable) queryVersion(filter string, orderBy string) (*versionable, error) {
   132  	result := versionable{}
   133  
   134  	values := url.Values{}
   135  	values.Set("$filter", filter)
   136  	values.Set("$orderby", orderBy)
   137  	values.Set("$select", "Name,Version,TechRelease,TechSpLevel,TechPatchLevel,Namespace") //Namespace needed otherwise empty result - will be fixed by OCS shortly
   138  	values.Set("$format", "json")
   139  	values.Set("$top", "1")
   140  
   141  	requestUrl := v.queryUrl + "?" + values.Encode()
   142  
   143  	if body, err := v.connector.Get(requestUrl); err != nil {
   144  		return &result, err
   145  	} else {
   146  		Versions := versionables{}
   147  		if err := json.Unmarshal(body, &Versions); err != nil {
   148  			return &result, errors.Wrap(err, "Unexpected AAKaaS response for Component Version Query: "+string(body))
   149  		}
   150  		switch len(Versions.Wrapper.Vs) {
   151  		case 0:
   152  			result = versionable{
   153  				TechRelease:    "0",
   154  				TechSpLevel:    "0000",
   155  				TechPatchLevel: "0000",
   156  			}
   157  		case 1:
   158  			result = Versions.Wrapper.Vs[0]
   159  		default:
   160  			return &result, errors.New("Unexpected Number of CVs in result: " + fmt.Sprint(len(Versions.Wrapper.Vs)))
   161  		}
   162  	}
   163  	log.Entry().Infof("... looked up highest existing package in AAKaaS of the codeline: %s.%s.%s", result.TechRelease, result.TechSpLevel, result.TechPatchLevel)
   164  	return &result, nil
   165  }
   166  
   167  func (v *versionable) getDottedVersionString() (string, error) {
   168  	var spLevelAsnumber int
   169  	var patchLevelAsNumber int
   170  	var err error
   171  	if spLevelAsnumber, err = strconv.Atoi(v.TechSpLevel); err != nil {
   172  		return "", err
   173  	}
   174  	if patchLevelAsNumber, err = strconv.Atoi(v.TechPatchLevel); err != nil {
   175  		return "", err
   176  	}
   177  	dottedVersionString := strings.Join([]string{v.TechRelease, strconv.Itoa(spLevelAsnumber), strconv.Itoa(patchLevelAsNumber)}, ".")
   178  	return dottedVersionString, nil
   179  }