github.com/ouraigua/jenkins-library@v0.0.0-20231028010029-fbeaf2f3aa9b/pkg/transportrequest/solman/upload.go (about)

     1  package solman
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/SAP/jenkins-library/pkg/config/validation"
     6  	"github.com/SAP/jenkins-library/pkg/log"
     7  	"github.com/pkg/errors"
     8  	"strings"
     9  )
    10  
    11  // FileSystem interface collecting everything which is file system
    12  // related and needed in the context of a SOLMAN upload.
    13  type FileSystem interface {
    14  	FileExists(path string) (bool, error)
    15  }
    16  
    17  // UploadAction Collects all the properties we need for the deployment
    18  type UploadAction struct {
    19  	Connection         Connection
    20  	ChangeDocumentID   string
    21  	TransportRequestID string
    22  	ApplicationID      string
    23  	File               string
    24  	CMOpts             []string
    25  }
    26  
    27  // Action collects everything which is needed to perform a SOLMAN upload
    28  type Action interface {
    29  	WithConnection(Connection)
    30  	WithChangeDocumentID(string)
    31  	WithTransportRequestID(string)
    32  	WithApplicationID(string)
    33  	WithFile(string)
    34  	WithCMOpts([]string)
    35  	Perform(fs FileSystem, command Exec) error
    36  }
    37  
    38  // WithConnection specifies all the connection details which
    39  // are required in order to connect to SOLMAN
    40  func (a *UploadAction) WithConnection(c Connection) {
    41  	a.Connection = c
    42  }
    43  
    44  // WithChangeDocumentID specifies the change document which
    45  // receives the executable.
    46  func (a *UploadAction) WithChangeDocumentID(id string) {
    47  	a.ChangeDocumentID = id
    48  }
    49  
    50  // WithTransportRequestID specifies the transport request which
    51  // receives the executable.
    52  func (a *UploadAction) WithTransportRequestID(id string) {
    53  	a.TransportRequestID = id
    54  }
    55  
    56  // WithApplicationID specifies the application ID.
    57  func (a *UploadAction) WithApplicationID(id string) {
    58  	a.ApplicationID = id
    59  }
    60  
    61  // WithFile specifies the executable which should be uploaded into
    62  // a transport on SOLMAN
    63  func (a *UploadAction) WithFile(f string) {
    64  	a.File = f
    65  }
    66  
    67  // WithCMOpts sets additional options for calling the
    68  // cm client tool. E.g. -D options. Useful for troubleshooting
    69  func (a *UploadAction) WithCMOpts(opts []string) {
    70  	a.CMOpts = opts
    71  }
    72  
    73  // Perform performs the SOLMAN upload
    74  func (a *UploadAction) Perform(fs FileSystem, command Exec) error {
    75  
    76  	log.Entry().Infof("Deploying artifact '%s' to '%s'.",
    77  		a.File, a.Connection.Endpoint)
    78  
    79  	missingParameters, err := validation.FindEmptyStringsInConfigStruct(*a)
    80  
    81  	if err == nil {
    82  		notInitialized := len(missingParameters) != 0
    83  		if notInitialized {
    84  			err = fmt.Errorf("the following parameters are not available '%s'", missingParameters)
    85  		}
    86  	}
    87  
    88  	if err == nil {
    89  		var exists bool
    90  		exists, err = fs.FileExists(a.File)
    91  
    92  		if err == nil && !exists {
    93  			err = fmt.Errorf("file '%s' does not exist", a.File)
    94  		}
    95  	}
    96  
    97  	if err == nil {
    98  		if len(a.CMOpts) > 0 {
    99  			command.SetEnv([]string{fmt.Sprintf("CMCLIENT_OPTS=%s", strings.Join(a.CMOpts, " "))})
   100  		}
   101  
   102  		err = command.RunExecutable("cmclient",
   103  			"--endpoint", a.Connection.Endpoint,
   104  			"--user", a.Connection.User,
   105  			"--password", a.Connection.Password,
   106  			"upload-file-to-transport",
   107  			"-cID", a.ChangeDocumentID,
   108  			"-tID", a.TransportRequestID,
   109  			a.ApplicationID, a.File)
   110  
   111  		exitCode := command.GetExitCode()
   112  
   113  		if exitCode != 0 {
   114  			message := fmt.Sprintf("upload command returned with exit code '%d'", exitCode)
   115  			if err != nil {
   116  				// Using the wrapping here is to some extend an abuse, since it is not really
   117  				// error chaining (the other error is not necessaryly a "predecessor" of this one).
   118  				// But it is a pragmatic approach for not loosing information for trouble shooting. There
   119  				// is no possibility to have something like suppressed errors.
   120  				err = errors.Wrap(err, message)
   121  			} else {
   122  				err = errors.New(message)
   123  			}
   124  		}
   125  	}
   126  
   127  	if err == nil {
   128  		log.Entry().Infof("Deployment succeeded, artifact: '%s', endpoint: '%s'",
   129  			a.File, a.Connection.Endpoint)
   130  	} else {
   131  		log.Entry().WithError(err).Warnf("Deployment failed, artifact: '%s', endpoint: '%s'",
   132  			a.File, a.Connection.Endpoint)
   133  	}
   134  
   135  	return errors.Wrapf(err, "cannot upload artifact '%s'", a.File)
   136  }