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 
			
		
		
		
	
		
			
				
	
	
		
			233 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			233 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package cmd
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	b64 "encoding/base64"
 | |
| 	"encoding/json"
 | |
| 	"fmt"
 | |
| 	"io/ioutil"
 | |
| 	"net/http"
 | |
| 	"path/filepath"
 | |
| 	"strings"
 | |
| 
 | |
| 	"github.com/Jeffail/gabs/v2"
 | |
| 	"github.com/SAP/jenkins-library/pkg/cpi"
 | |
| 	piperhttp "github.com/SAP/jenkins-library/pkg/http"
 | |
| 	"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"
 | |
| )
 | |
| 
 | |
| type integrationArtifactResourceData struct {
 | |
| 	Method     string
 | |
| 	URL        string
 | |
| 	IFlowID    string
 | |
| 	ScsMessage string
 | |
| 	FlrMessage string
 | |
| 	StatusCode int
 | |
| }
 | |
| 
 | |
| func integrationArtifactResource(config integrationArtifactResourceOptions, telemetryData *telemetry.CustomData) {
 | |
| 	// Utils can be used wherever the command.ExecRunner interface is expected.
 | |
| 	// It can also be used for example as a mavenExecRunner.
 | |
| 	httpClient := &piperhttp.Client{}
 | |
| 	fileUtils := &piperutils.Files{}
 | |
| 
 | |
| 	// For HTTP calls import  piperhttp "github.com/SAP/jenkins-library/pkg/http"
 | |
| 	// and use a  &piperhttp.Client{} in a custom system
 | |
| 	// Example: step checkmarxExecuteScan.go
 | |
| 
 | |
| 	// Error situations should be bubbled up until they reach the line below which will then stop execution
 | |
| 	// through the log.Entry().Fatal() call leading to an os.Exit(1) in the end.
 | |
| 	err := runIntegrationArtifactResource(&config, telemetryData, fileUtils, httpClient)
 | |
| 	if err != nil {
 | |
| 		log.Entry().WithError(err).Fatal("step execution failed")
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func runIntegrationArtifactResource(config *integrationArtifactResourceOptions, telemetryData *telemetry.CustomData, fileUtils piperutils.FileUtils, httpClient piperhttp.Sender) error {
 | |
| 	serviceKey, err := cpi.ReadCpiServiceKey(config.APIServiceKey)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	clientOptions := piperhttp.ClientOptions{}
 | |
| 	header := make(http.Header)
 | |
| 	header.Add("Accept", "application/json")
 | |
| 	tokenParameters := cpi.TokenParameters{TokenURL: serviceKey.OAuth.OAuthTokenProviderURL, Username: serviceKey.OAuth.ClientID, Password: serviceKey.OAuth.ClientSecret, Client: httpClient}
 | |
| 	token, err := cpi.CommonUtils.GetBearerToken(tokenParameters)
 | |
| 	if err != nil {
 | |
| 		return errors.Wrap(err, "failed to fetch Bearer Token")
 | |
| 	}
 | |
| 	clientOptions.Token = fmt.Sprintf("Bearer %s", token)
 | |
| 	httpClient.SetOptions(clientOptions)
 | |
| 	mode := strings.ToLower(strings.TrimSpace(config.Operation))
 | |
| 	switch mode {
 | |
| 	case "create":
 | |
| 		return UploadIntegrationArtifactResource(config, httpClient, fileUtils, serviceKey.OAuth.Host)
 | |
| 	case "update":
 | |
| 		return UpdateIntegrationArtifactResource(config, httpClient, fileUtils, serviceKey.OAuth.Host)
 | |
| 	case "delete":
 | |
| 		return DeleteIntegrationArtifactResource(config, httpClient, fileUtils, serviceKey.OAuth.Host)
 | |
| 	default:
 | |
| 		return errors.New("invalid input for resource operation")
 | |
| 	}
 | |
| }
 | |
| 
 | |
| //UploadIntegrationArtifactResource - Upload new resource file to existing integration flow design time artefact
 | |
| func UploadIntegrationArtifactResource(config *integrationArtifactResourceOptions, httpClient piperhttp.Sender, fileUtils piperutils.FileUtils, apiHost string) error {
 | |
| 	httpMethod := "POST"
 | |
| 	uploadIflowStatusURL := fmt.Sprintf("%s/api/v1/IntegrationDesigntimeArtifacts(Id='%s',Version='%s')/Resources", apiHost, config.IntegrationFlowID, "Active")
 | |
| 	header := make(http.Header)
 | |
| 	header.Add("content-type", "application/json")
 | |
| 	payload, jsonError := GetJSONPayload(config, "create", fileUtils)
 | |
| 	if jsonError != nil {
 | |
| 		return errors.Wrapf(jsonError, "Failed to get json payload for file %v, failed with error", config.ResourcePath)
 | |
| 	}
 | |
| 
 | |
| 	uploadIflowStatusResp, httpErr := httpClient.SendRequest(httpMethod, uploadIflowStatusURL, payload, header, nil)
 | |
| 
 | |
| 	successMessage := "Successfully create a new resource file in the integration flow artefact"
 | |
| 	failureMessage := "Failed to create a new resource file in the integration flow artefact"
 | |
| 	integrationArtifactResourceData := integrationArtifactResourceData{
 | |
| 		Method:     httpMethod,
 | |
| 		URL:        uploadIflowStatusURL,
 | |
| 		IFlowID:    config.IntegrationFlowID,
 | |
| 		ScsMessage: successMessage,
 | |
| 		FlrMessage: failureMessage,
 | |
| 		StatusCode: http.StatusCreated,
 | |
| 	}
 | |
| 
 | |
| 	return HttpResponseHandler(uploadIflowStatusResp, httpErr, &integrationArtifactResourceData)
 | |
| }
 | |
| 
 | |
| //UpdateIntegrationArtifactResource - Update integration artifact resource file
 | |
| func UpdateIntegrationArtifactResource(config *integrationArtifactResourceOptions, httpClient piperhttp.Sender, fileUtils piperutils.FileUtils, apiHost string) error {
 | |
| 	httpMethod := "PUT"
 | |
| 	header := make(http.Header)
 | |
| 	header.Add("content-type", "application/json")
 | |
| 	fileName := filepath.Base(config.ResourcePath)
 | |
| 	fileExt := GetResourceFileExtension(fileName)
 | |
| 	if fileExt == "" {
 | |
| 		return errors.New("invalid file extension in resource file")
 | |
| 	}
 | |
| 	updateIflowStatusURL := fmt.Sprintf("%s/api/v1/IntegrationDesigntimeArtifacts(Id='%s',Version='%s')/$links/Resources(Name='%s',ResourceType='%s')", apiHost, config.IntegrationFlowID, "Active", fileName, fileExt)
 | |
| 	payload, jsonError := GetJSONPayload(config, "update", fileUtils)
 | |
| 	if jsonError != nil {
 | |
| 		return errors.Wrapf(jsonError, "Failed to get json payload for file %v, failed with error", config.ResourcePath)
 | |
| 	}
 | |
| 	updateIflowStatusResp, httpErr := httpClient.SendRequest(httpMethod, updateIflowStatusURL, payload, header, nil)
 | |
| 
 | |
| 	successMessage := "Successfully updated resource file of the integration flow artefact"
 | |
| 	failureMessage := "Failed to update rsource file of the integration flow artefact"
 | |
| 	integrationArtifactResourceData := integrationArtifactResourceData{
 | |
| 		Method:     httpMethod,
 | |
| 		URL:        updateIflowStatusURL,
 | |
| 		IFlowID:    config.IntegrationFlowID,
 | |
| 		ScsMessage: successMessage,
 | |
| 		FlrMessage: failureMessage,
 | |
| 		StatusCode: http.StatusOK,
 | |
| 	}
 | |
| 
 | |
| 	return HttpResponseHandler(updateIflowStatusResp, httpErr, &integrationArtifactResourceData)
 | |
| }
 | |
| 
 | |
| //DeleteIntegrationArtifactResource - Delete integration artifact resource file
 | |
| func DeleteIntegrationArtifactResource(config *integrationArtifactResourceOptions, httpClient piperhttp.Sender, fileUtils piperutils.FileUtils, apiHost string) error {
 | |
| 	httpMethod := "DELETE"
 | |
| 	header := make(http.Header)
 | |
| 	header.Add("content-type", "application/json")
 | |
| 	fileName := filepath.Base(config.ResourcePath)
 | |
| 	fileExt := GetResourceFileExtension(fileName)
 | |
| 	if fileExt == "" {
 | |
| 		return errors.New("invalid file extension in resource file")
 | |
| 	}
 | |
| 	deleteIflowResourceStatusURL := fmt.Sprintf("%s/api/v1/IntegrationDesigntimeArtifacts(Id='%s',Version='%s')/$links/Resources(Name='%s',ResourceType='%s')", apiHost, config.IntegrationFlowID, "Active", fileName, fileExt)
 | |
| 	deleteIflowResourceStatusResp, httpErr := httpClient.SendRequest(httpMethod, deleteIflowResourceStatusURL, nil, header, nil)
 | |
| 
 | |
| 	successMessage := "Successfully deleted a resource file in the integration flow artefact"
 | |
| 	failureMessage := "Failed to delete a resource file in the integration flow artefact"
 | |
| 	integrationArtifactResourceData := integrationArtifactResourceData{
 | |
| 		Method:     httpMethod,
 | |
| 		URL:        deleteIflowResourceStatusURL,
 | |
| 		IFlowID:    config.IntegrationFlowID,
 | |
| 		ScsMessage: successMessage,
 | |
| 		FlrMessage: failureMessage,
 | |
| 		StatusCode: http.StatusOK,
 | |
| 	}
 | |
| 
 | |
| 	return HttpResponseHandler(deleteIflowResourceStatusResp, httpErr, &integrationArtifactResourceData)
 | |
| }
 | |
| 
 | |
| //GetJSONPayload -return http payload as byte array
 | |
| func GetJSONPayload(config *integrationArtifactResourceOptions, mode string, fileUtils piperutils.FileUtils) (*bytes.Buffer, error) {
 | |
| 	fileContent, readError := fileUtils.FileRead(config.ResourcePath)
 | |
| 	if readError != nil {
 | |
| 		return nil, errors.Wrapf(readError, "Error reading file")
 | |
| 	}
 | |
| 	fileName := filepath.Base(config.ResourcePath)
 | |
| 	jsonObj := gabs.New()
 | |
| 	if mode == "create" {
 | |
| 		jsonObj.Set(fileName, "Name")
 | |
| 		jsonObj.Set(GetResourceFileExtension(fileName), "ResourceType")
 | |
| 		jsonObj.Set(b64.StdEncoding.EncodeToString(fileContent), "ResourceContent")
 | |
| 	} else if mode == "update" {
 | |
| 		jsonObj.Set(b64.StdEncoding.EncodeToString(fileContent), "ResourceContent")
 | |
| 	} else {
 | |
| 		return nil, fmt.Errorf("Unkown node: '%s'", mode)
 | |
| 	}
 | |
| 
 | |
| 	jsonBody, jsonErr := json.Marshal(jsonObj)
 | |
| 
 | |
| 	if jsonErr != nil {
 | |
| 		return nil, errors.Wrapf(jsonErr, "json payload is invalid for integration flow artifact %q", config.IntegrationFlowID)
 | |
| 	}
 | |
| 	return bytes.NewBuffer(jsonBody), nil
 | |
| }
 | |
| 
 | |
| //GetResourceFileExtension -return resource file extension
 | |
| func GetResourceFileExtension(filename string) string {
 | |
| 	fileExtension := filepath.Ext(filename)
 | |
| 	switch fileExtension {
 | |
| 	case ".xsl":
 | |
| 		return "xslt"
 | |
| 	case ".gsh", ".groovy":
 | |
| 		return "groovy"
 | |
| 	case ".js":
 | |
| 		return "js"
 | |
| 	case ".jar":
 | |
| 		return "jar"
 | |
| 	default:
 | |
| 		return ""
 | |
| 	}
 | |
| }
 | |
| 
 | |
| //HttpResponseHandler - handle http response object
 | |
| func HttpResponseHandler(resp *http.Response, httpErr error, integrationArtifactResourceData *integrationArtifactResourceData) error {
 | |
| 
 | |
| 	if resp != nil && resp.Body != nil {
 | |
| 		defer resp.Body.Close()
 | |
| 	}
 | |
| 
 | |
| 	if resp == nil {
 | |
| 		return errors.Errorf("did not retrieve a HTTP response: %v", httpErr)
 | |
| 	}
 | |
| 
 | |
| 	if resp.StatusCode == integrationArtifactResourceData.StatusCode {
 | |
| 		log.Entry().
 | |
| 			WithField("IntegrationFlowID", integrationArtifactResourceData.IFlowID).
 | |
| 			Info(integrationArtifactResourceData.ScsMessage)
 | |
| 		return nil
 | |
| 	}
 | |
| 	if httpErr != nil {
 | |
| 		responseBody, readErr := ioutil.ReadAll(resp.Body)
 | |
| 		if readErr != nil {
 | |
| 			return errors.Wrapf(readErr, "HTTP response body could not be read, Response status code: %v", resp.StatusCode)
 | |
| 		}
 | |
| 		log.Entry().Errorf("a HTTP error occurred! Response body: %v, Response status code: %v", string(responseBody), resp.StatusCode)
 | |
| 		return errors.Wrapf(httpErr, "HTTP %v request to %v failed with error: %v", integrationArtifactResourceData.Method, integrationArtifactResourceData.URL, string(responseBody))
 | |
| 	}
 | |
| 	return errors.Errorf("%s, Response Status code: %v", integrationArtifactResourceData.FlrMessage, resp.StatusCode)
 | |
| }
 |