github.com/ouraigua/jenkins-library@v0.0.0-20231028010029-fbeaf2f3aa9b/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/piperutils"
    11  
    12  	"github.com/SAP/jenkins-library/pkg/maven"
    13  )
    14  
    15  // Coordinates to address the artifact coordinates like groupId, artifactId, version and packaging
    16  type Coordinates struct {
    17  	GroupID    string
    18  	ArtifactID string
    19  	Version    string
    20  	Packaging  string
    21  }
    22  
    23  // Artifact defines the versioning operations for various build tools
    24  type Artifact interface {
    25  	VersioningScheme() string
    26  	GetVersion() (string, error)
    27  	SetVersion(string) error
    28  	GetCoordinates() (Coordinates, error)
    29  }
    30  
    31  // Options define build tool specific settings in order to properly retrieve e.g. the version / coordinates of an artifact
    32  type Options struct {
    33  	ProjectSettingsFile  string
    34  	DockerImage          string
    35  	GlobalSettingsFile   string
    36  	M2Path               string
    37  	Defines              []string
    38  	VersionSource        string
    39  	VersionSection       string
    40  	VersionField         string
    41  	VersioningScheme     string
    42  	HelmUpdateAppVersion bool
    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  	switch buildTool {
    79  	case "custom":
    80  		var err error
    81  		artifact, err = customArtifact(buildDescriptorFilePath, opts.VersionField, opts.VersionSection, opts.VersioningScheme)
    82  		if err != nil {
    83  			return artifact, err
    84  		}
    85  	case "docker":
    86  		artifact = &Docker{
    87  			utils:            utils,
    88  			options:          opts,
    89  			path:             buildDescriptorFilePath,
    90  			versionSource:    opts.VersionSource,
    91  			versioningScheme: opts.VersioningScheme,
    92  		}
    93  	case "dub":
    94  		if len(buildDescriptorFilePath) == 0 {
    95  			buildDescriptorFilePath = "dub.json"
    96  		}
    97  		artifact = &JSONfile{
    98  			path:         buildDescriptorFilePath,
    99  			versionField: "version",
   100  		}
   101  	case "gradle":
   102  		if len(buildDescriptorFilePath) == 0 {
   103  			buildDescriptorFilePath = "gradle.properties"
   104  		}
   105  		artifact = &Gradle{
   106  			path:         buildDescriptorFilePath,
   107  			versionField: opts.VersionField,
   108  			utils:        utils,
   109  		}
   110  	case "golang":
   111  		if len(buildDescriptorFilePath) == 0 {
   112  			var err error
   113  			buildDescriptorFilePath, err = searchDescriptor([]string{"go.mod", "VERSION", "version.txt"}, fileExists)
   114  			if err != nil {
   115  				return artifact, err
   116  			}
   117  		}
   118  
   119  		switch buildDescriptorFilePath {
   120  		case "go.mod":
   121  			artifact = &GoMod{path: buildDescriptorFilePath, fileExists: fileExists}
   122  			break
   123  		default:
   124  			artifact = &Versionfile{path: buildDescriptorFilePath}
   125  		}
   126  	case "helm":
   127  		artifact = &HelmChart{
   128  			path:             buildDescriptorFilePath,
   129  			utils:            utils,
   130  			updateAppVersion: opts.HelmUpdateAppVersion,
   131  		}
   132  	case "maven":
   133  		if len(buildDescriptorFilePath) == 0 {
   134  			buildDescriptorFilePath = "pom.xml"
   135  		}
   136  		artifact = &Maven{
   137  			runner: &mvnRunner{},
   138  			utils:  utils,
   139  			options: maven.EvaluateOptions{
   140  				PomPath:             buildDescriptorFilePath,
   141  				ProjectSettingsFile: opts.ProjectSettingsFile,
   142  				GlobalSettingsFile:  opts.GlobalSettingsFile,
   143  				M2Path:              opts.M2Path,
   144  				Defines:             opts.Defines,
   145  			},
   146  		}
   147  	case "mta":
   148  		if len(buildDescriptorFilePath) == 0 {
   149  			buildDescriptorFilePath = "mta.yaml"
   150  		}
   151  		artifact = &YAMLfile{
   152  			path:            buildDescriptorFilePath,
   153  			versionField:    "version",
   154  			artifactIDField: "ID",
   155  		}
   156  	case "npm", "yarn":
   157  		if len(buildDescriptorFilePath) == 0 {
   158  			buildDescriptorFilePath = "package.json"
   159  		}
   160  		artifact = &JSONfile{
   161  			path:         buildDescriptorFilePath,
   162  			versionField: "version",
   163  		}
   164  	case "pip":
   165  		if len(buildDescriptorFilePath) == 0 {
   166  			var err error
   167  			buildDescriptorFilePath, err = searchDescriptor([]string{"setup.py", "version.txt", "VERSION"}, fileExists)
   168  			if err != nil {
   169  				return artifact, err
   170  			}
   171  		}
   172  		artifact = &Pip{
   173  			path:       buildDescriptorFilePath,
   174  			fileExists: fileExists,
   175  		}
   176  	case "sbt":
   177  		if len(buildDescriptorFilePath) == 0 {
   178  			var err error
   179  			buildDescriptorFilePath, err = searchDescriptor([]string{"sbtDescriptor.json", "build.sbt"}, fileExists)
   180  			if err != nil {
   181  				return artifact, err
   182  			}
   183  		}
   184  		artifact = &JSONfile{
   185  			path:         buildDescriptorFilePath,
   186  			versionField: "version",
   187  		}
   188  	default:
   189  		return artifact, fmt.Errorf("build tool '%v' not supported", buildTool)
   190  	}
   191  
   192  	return artifact, nil
   193  }
   194  
   195  func searchDescriptor(supported []string, existsFunc func(string) (bool, error)) (string, error) {
   196  	var descriptor string
   197  	for _, f := range supported {
   198  		exists, _ := existsFunc(f)
   199  		if exists {
   200  			descriptor = f
   201  			break
   202  		}
   203  	}
   204  	if len(descriptor) == 0 {
   205  		return "", fmt.Errorf("no build descriptor available, supported: %v", supported)
   206  	}
   207  	return descriptor, nil
   208  }
   209  
   210  func customArtifact(buildDescriptorFilePath, field, section, scheme string) (Artifact, error) {
   211  	switch filepath.Ext(buildDescriptorFilePath) {
   212  	case ".cfg", ".ini":
   213  		return &INIfile{
   214  			path:             buildDescriptorFilePath,
   215  			versionField:     field,
   216  			versionSection:   section,
   217  			versioningScheme: scheme,
   218  		}, nil
   219  	case ".json":
   220  		return &JSONfile{
   221  			path:         buildDescriptorFilePath,
   222  			versionField: field,
   223  		}, nil
   224  	case ".yaml", ".yml":
   225  		return &YAMLfile{
   226  			path:         buildDescriptorFilePath,
   227  			versionField: field,
   228  		}, nil
   229  	case ".txt", "":
   230  		return &Versionfile{
   231  			path:             buildDescriptorFilePath,
   232  			versioningScheme: scheme,
   233  		}, nil
   234  	default:
   235  		return nil, fmt.Errorf("file type not supported: '%v'", buildDescriptorFilePath)
   236  	}
   237  }