github.com/SAP/jenkins-library@v1.362.0/pkg/versioning/versioning.go (about)

     1  package versioning
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"net/http"
     7  	"os"
     8  	"path/filepath"
     9  
    10  	"github.com/SAP/jenkins-library/pkg/maven"
    11  	"github.com/SAP/jenkins-library/pkg/piperutils"
    12  )
    13  
    14  // Coordinates to address the artifact coordinates like groupId, artifactId, version and packaging
    15  type Coordinates struct {
    16  	GroupID    string
    17  	ArtifactID string
    18  	Version    string
    19  	Packaging  string
    20  }
    21  
    22  // Artifact defines the versioning operations for various build tools
    23  type Artifact interface {
    24  	VersioningScheme() string
    25  	GetVersion() (string, error)
    26  	SetVersion(string) error
    27  	GetCoordinates() (Coordinates, error)
    28  }
    29  
    30  // Options define build tool specific settings in order to properly retrieve e.g. the version / coordinates of an artifact
    31  type Options struct {
    32  	ProjectSettingsFile     string
    33  	DockerImage             string
    34  	GlobalSettingsFile      string
    35  	M2Path                  string
    36  	Defines                 []string
    37  	VersionSource           string
    38  	VersionSection          string
    39  	VersionField            string
    40  	VersioningScheme        string
    41  	HelmUpdateAppVersion    bool
    42  	CAPVersioningPreference string
    43  }
    44  
    45  // Utils defines the versioning operations for various build tools
    46  type Utils interface {
    47  	Stdout(out io.Writer)
    48  	Stderr(err io.Writer)
    49  	RunExecutable(e string, p ...string) error
    50  
    51  	DownloadFile(url, filename string, header http.Header, cookies []*http.Cookie) error
    52  	Glob(pattern string) (matches []string, err error)
    53  	FileExists(filename string) (bool, error)
    54  	Copy(src, dest string) (int64, error)
    55  	MkdirAll(path string, perm os.FileMode) error
    56  	FileWrite(path string, content []byte, perm os.FileMode) error
    57  	FileRead(path string) ([]byte, error)
    58  	FileRemove(path string) error
    59  }
    60  
    61  type mvnRunner struct{}
    62  
    63  func (m *mvnRunner) Execute(options *maven.ExecuteOptions, utils maven.Utils) (string, error) {
    64  	return maven.Execute(options, utils)
    65  }
    66  func (m *mvnRunner) Evaluate(options *maven.EvaluateOptions, expression string, utils maven.Utils) (string, error) {
    67  	return maven.Evaluate(options, expression, utils)
    68  }
    69  
    70  var fileExists func(string) (bool, error)
    71  
    72  // GetArtifact returns the build tool specific implementation for retrieving version, etc. of an artifact
    73  func GetArtifact(buildTool, buildDescriptorFilePath string, opts *Options, utils Utils) (Artifact, error) {
    74  	var artifact Artifact
    75  	if fileExists == nil {
    76  		fileExists = piperutils.FileExists
    77  	}
    78  
    79  	// CAPVersioningPreference can only be 'maven' or 'npm'. Verification done on artifactPrepareVersion.yaml level
    80  	if buildTool == "CAP" {
    81  		buildTool = opts.CAPVersioningPreference
    82  	}
    83  
    84  	switch buildTool {
    85  	case "custom":
    86  		var err error
    87  		artifact, err = customArtifact(buildDescriptorFilePath, opts.VersionField, opts.VersionSection, opts.VersioningScheme)
    88  		if err != nil {
    89  			return artifact, err
    90  		}
    91  	case "docker":
    92  		artifact = &Docker{
    93  			utils:            utils,
    94  			options:          opts,
    95  			path:             buildDescriptorFilePath,
    96  			versionSource:    opts.VersionSource,
    97  			versioningScheme: opts.VersioningScheme,
    98  		}
    99  	case "dub":
   100  		if len(buildDescriptorFilePath) == 0 {
   101  			buildDescriptorFilePath = "dub.json"
   102  		}
   103  		artifact = &JSONfile{
   104  			path:         buildDescriptorFilePath,
   105  			versionField: "version",
   106  		}
   107  	case "gradle":
   108  		if len(buildDescriptorFilePath) == 0 {
   109  			buildDescriptorFilePath = "gradle.properties"
   110  		}
   111  		artifact = &Gradle{
   112  			path:         buildDescriptorFilePath,
   113  			versionField: opts.VersionField,
   114  			utils:        utils,
   115  		}
   116  	case "golang":
   117  		if len(buildDescriptorFilePath) == 0 {
   118  			var err error
   119  			buildDescriptorFilePath, err = searchDescriptor([]string{"go.mod", "VERSION", "version.txt"}, fileExists)
   120  			if err != nil {
   121  				return artifact, err
   122  			}
   123  		}
   124  
   125  		switch buildDescriptorFilePath {
   126  		case "go.mod":
   127  			artifact = &GoMod{path: buildDescriptorFilePath, fileExists: fileExists}
   128  			break
   129  		default:
   130  			artifact = &Versionfile{path: buildDescriptorFilePath}
   131  		}
   132  	case "helm":
   133  		artifact = &HelmChart{
   134  			path:             buildDescriptorFilePath,
   135  			utils:            utils,
   136  			updateAppVersion: opts.HelmUpdateAppVersion,
   137  		}
   138  	case "maven":
   139  		if len(buildDescriptorFilePath) == 0 {
   140  			buildDescriptorFilePath = "pom.xml"
   141  		}
   142  		artifact = &Maven{
   143  			runner: &mvnRunner{},
   144  			utils:  utils,
   145  			options: maven.EvaluateOptions{
   146  				PomPath:             buildDescriptorFilePath,
   147  				ProjectSettingsFile: opts.ProjectSettingsFile,
   148  				GlobalSettingsFile:  opts.GlobalSettingsFile,
   149  				M2Path:              opts.M2Path,
   150  				Defines:             opts.Defines,
   151  			},
   152  		}
   153  	case "mta":
   154  		if len(buildDescriptorFilePath) == 0 {
   155  			buildDescriptorFilePath = "mta.yaml"
   156  		}
   157  		artifact = &YAMLfile{
   158  			path:            buildDescriptorFilePath,
   159  			versionField:    "version",
   160  			artifactIDField: "ID",
   161  		}
   162  	case "npm", "yarn":
   163  		if len(buildDescriptorFilePath) == 0 {
   164  			buildDescriptorFilePath = "package.json"
   165  		}
   166  		artifact = &JSONfile{
   167  			path:         buildDescriptorFilePath,
   168  			versionField: "version",
   169  		}
   170  	case "pip":
   171  		if len(buildDescriptorFilePath) == 0 {
   172  			var err error
   173  			buildDescriptorFilePath, err = searchDescriptor([]string{"setup.py", "version.txt", "VERSION"}, fileExists)
   174  			if err != nil {
   175  				return artifact, err
   176  			}
   177  		}
   178  		artifact = &Pip{
   179  			path:       buildDescriptorFilePath,
   180  			fileExists: fileExists,
   181  		}
   182  	case "sbt":
   183  		if len(buildDescriptorFilePath) == 0 {
   184  			var err error
   185  			buildDescriptorFilePath, err = searchDescriptor([]string{"sbtDescriptor.json", "build.sbt"}, fileExists)
   186  			if err != nil {
   187  				return artifact, err
   188  			}
   189  		}
   190  		artifact = &JSONfile{
   191  			path:         buildDescriptorFilePath,
   192  			versionField: "version",
   193  		}
   194  	default:
   195  		return artifact, fmt.Errorf("build tool '%v' not supported", buildTool)
   196  	}
   197  
   198  	return artifact, nil
   199  }
   200  
   201  func searchDescriptor(supported []string, existsFunc func(string) (bool, error)) (string, error) {
   202  	var descriptor string
   203  	for _, f := range supported {
   204  		exists, _ := existsFunc(f)
   205  		if exists {
   206  			descriptor = f
   207  			break
   208  		}
   209  	}
   210  	if len(descriptor) == 0 {
   211  		return "", fmt.Errorf("no build descriptor available, supported: %v", supported)
   212  	}
   213  	return descriptor, nil
   214  }
   215  
   216  func customArtifact(buildDescriptorFilePath, field, section, scheme string) (Artifact, error) {
   217  	switch filepath.Ext(buildDescriptorFilePath) {
   218  	case ".cfg", ".ini":
   219  		return &INIfile{
   220  			path:             buildDescriptorFilePath,
   221  			versionField:     field,
   222  			versionSection:   section,
   223  			versioningScheme: scheme,
   224  		}, nil
   225  	case ".json":
   226  		return &JSONfile{
   227  			path:         buildDescriptorFilePath,
   228  			versionField: field,
   229  		}, nil
   230  	case ".yaml", ".yml":
   231  		return &YAMLfile{
   232  			path:         buildDescriptorFilePath,
   233  			versionField: field,
   234  		}, nil
   235  	case ".txt", "":
   236  		return &Versionfile{
   237  			path:             buildDescriptorFilePath,
   238  			versioningScheme: scheme,
   239  		}, nil
   240  	default:
   241  		return nil, fmt.Errorf("file type not supported: '%v'", buildDescriptorFilePath)
   242  	}
   243  }