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 
			
		
		
		
	artifactPrepareVersioning: support more buildTools (#1367)
* artifactPrepareVersioning: support more buildTools
This commit is contained in:
		| @@ -67,12 +67,16 @@ func runArtifactPrepareVersion(config *artifactPrepareVersionOptions, telemetryD | ||||
|  | ||||
| 	telemetryData.Custom1Label = "buildTool" | ||||
| 	telemetryData.Custom1 = config.BuildTool | ||||
| 	telemetryData.Custom2Label = "filePath" | ||||
| 	telemetryData.Custom2 = config.FilePath | ||||
|  | ||||
| 	// Options for artifact | ||||
| 	artifactOpts := versioning.Options{ | ||||
| 		GlobalSettingsFile:  config.GlobalSettingsFile, | ||||
| 		M2Path:              config.M2Path, | ||||
| 		ProjectSettingsFile: config.ProjectSettingsFile, | ||||
| 		VersionField:        config.CustomversionField, | ||||
| 		VersionSection:      config.CustomVersionSection, | ||||
| 	} | ||||
|  | ||||
| 	var err error | ||||
|   | ||||
| @@ -16,19 +16,21 @@ import ( | ||||
| ) | ||||
|  | ||||
| type artifactPrepareVersionOptions struct { | ||||
| 	BuildTool           string `json:"buildTool,omitempty"` | ||||
| 	CommitUserName      string `json:"commitUserName,omitempty"` | ||||
| 	DockerVersionSource string `json:"dockerVersionSource,omitempty"` | ||||
| 	FilePath            string `json:"filePath,omitempty"` | ||||
| 	GlobalSettingsFile  string `json:"globalSettingsFile,omitempty"` | ||||
| 	IncludeCommitID     bool   `json:"includeCommitId,omitempty"` | ||||
| 	M2Path              string `json:"m2Path,omitempty"` | ||||
| 	Password            string `json:"password,omitempty"` | ||||
| 	ProjectSettingsFile string `json:"projectSettingsFile,omitempty"` | ||||
| 	TagPrefix           string `json:"tagPrefix,omitempty"` | ||||
| 	Username            string `json:"username,omitempty"` | ||||
| 	VersioningTemplate  string `json:"versioningTemplate,omitempty"` | ||||
| 	VersioningType      string `json:"versioningType,omitempty"` | ||||
| 	BuildTool            string `json:"buildTool,omitempty"` | ||||
| 	CommitUserName       string `json:"commitUserName,omitempty"` | ||||
| 	CustomversionField   string `json:"customversionField,omitempty"` | ||||
| 	CustomVersionSection string `json:"customVersionSection,omitempty"` | ||||
| 	DockerVersionSource  string `json:"dockerVersionSource,omitempty"` | ||||
| 	FilePath             string `json:"filePath,omitempty"` | ||||
| 	GlobalSettingsFile   string `json:"globalSettingsFile,omitempty"` | ||||
| 	IncludeCommitID      bool   `json:"includeCommitId,omitempty"` | ||||
| 	M2Path               string `json:"m2Path,omitempty"` | ||||
| 	Password             string `json:"password,omitempty"` | ||||
| 	ProjectSettingsFile  string `json:"projectSettingsFile,omitempty"` | ||||
| 	TagPrefix            string `json:"tagPrefix,omitempty"` | ||||
| 	Username             string `json:"username,omitempty"` | ||||
| 	VersioningTemplate   string `json:"versioningTemplate,omitempty"` | ||||
| 	VersioningType       string `json:"versioningType,omitempty"` | ||||
| } | ||||
|  | ||||
| type artifactPrepareVersionCommonPipelineEnvironment struct { | ||||
| @@ -107,7 +109,33 @@ The version is then either manually set by the team in the course of the develop | ||||
|  | ||||
| Unlike for the _Continuous Deloyment_ pattern descibed above, in this case there is no dedicated tagging required for the build process since the version is already available in the repository. | ||||
|  | ||||
| Configuration of this pattern is done via ` + "`" + `versioningType: library` + "`" + `.`, | ||||
| Configuration of this pattern is done via ` + "`" + `versioningType: library` + "`" + `. | ||||
|  | ||||
| ### Support of additional build tools | ||||
|  | ||||
| Besides the ` + "`" + `buildTools` + "`" + ` provided out of the box (like ` + "`" + `maven` + "`" + `, ` + "`" + `mta` + "`" + `, ` + "`" + `npm` + "`" + `, ...) it is possible to set ` + "`" + `buildTool: custom` + "`" + `. | ||||
|  | ||||
| This allows you to provide automatic versioning for tools using a: | ||||
|  | ||||
| #### file with the version as only content: | ||||
|  | ||||
| Define ` + "`" + `buildTool: custom` + "`" + ` as well as ` + "`" + `filePath: <path to your file>` + "`" + ` | ||||
|  | ||||
| **Please note:** ` + "`" + `<path to your file>` + "`" + ` need to point either to a ` + "`" + `*.txt` + "`" + ` file or to a file without extension. | ||||
|  | ||||
| #### ` + "`" + `ini` + "`" + ` file containing the version: | ||||
|  | ||||
| Define ` + "`" + `buildTool: custom` + "`" + `, ` + "`" + `filePath: <path to your ini-file>` + "`" + ` as well as parameters ` + "`" + `versionSection` + "`" + ` and ` + "`" + `versionSource` + "`" + ` to point to the version location (section & parameter name) within the file. | ||||
|  | ||||
| **Please note:** ` + "`" + `<path to your file>` + "`" + ` need to point either to a ` + "`" + `*.cfg` + "`" + ` or a ` + "`" + `*.ini` + "`" + ` file. | ||||
|  | ||||
| #### ` + "`" + `json` + "`" + ` file containing the version: | ||||
|  | ||||
| Define ` + "`" + `buildTool: custom` + "`" + `, ` + "`" + `filePath: <path to your *.json file` + "`" + ` as well as parameter ` + "`" + `versionSource` + "`" + ` to point to the parameter containing the version. | ||||
|  | ||||
| #### ` + "`" + `yaml` + "`" + ` file containing the version | ||||
|  | ||||
| Define ` + "`" + `buildTool: custom` + "`" + `, ` + "`" + `filePath: <path to your *.yml/*.yaml file` + "`" + ` as well as parameter ` + "`" + `versionSource` + "`" + ` to point to the parameter containing the version.`, | ||||
| 		PreRunE: func(cmd *cobra.Command, args []string) error { | ||||
| 			startTime = time.Now() | ||||
| 			log.SetStepName("artifactPrepareVersion") | ||||
| @@ -135,9 +163,11 @@ Configuration of this pattern is done via ` + "`" + `versioningType: library` + | ||||
| } | ||||
|  | ||||
| func addArtifactPrepareVersionFlags(cmd *cobra.Command, stepConfig *artifactPrepareVersionOptions) { | ||||
| 	cmd.Flags().StringVar(&stepConfig.BuildTool, "buildTool", os.Getenv("PIPER_buildTool"), "Defines the tool which is used for building the artifact.") | ||||
| 	cmd.Flags().StringVar(&stepConfig.BuildTool, "buildTool", os.Getenv("PIPER_buildTool"), "Defines the tool which is used for building the artifact. Supports `custom`, `dub`, `golang`, `maven`, `mta`, `npm`, `pip`, `sbt`.") | ||||
| 	cmd.Flags().StringVar(&stepConfig.CommitUserName, "commitUserName", "Project Piper", "Defines the user name which appears in version control for the versioning update (in case `versioningType: cloud`).") | ||||
| 	cmd.Flags().StringVar(&stepConfig.DockerVersionSource, "dockerVersionSource", os.Getenv("PIPER_dockerVersionSource"), "For Docker only: Specifies the source to be used for for generating the automatic version. * This can either be the version of the base image - as retrieved from the `FROM` statement within the Dockerfile, e.g. `FROM jenkins:2.46.2` * Alternatively the name of an environment variable defined in the Docker image can be used which contains the version number, e.g. `ENV MY_VERSION 1.2.3`.") | ||||
| 	cmd.Flags().StringVar(&stepConfig.CustomversionField, "customversionField", os.Getenv("PIPER_customversionField"), "For `buildTool: custom`: Defines the field which contains the version in the descriptor file.") | ||||
| 	cmd.Flags().StringVar(&stepConfig.CustomVersionSection, "customVersionSection", os.Getenv("PIPER_customVersionSection"), "For `buildTool: custom`: Defines the section for version retrieval in vase a *.ini/*.cfg file is used.") | ||||
| 	cmd.Flags().StringVar(&stepConfig.DockerVersionSource, "dockerVersionSource", os.Getenv("PIPER_dockerVersionSource"), "For `buildTool: docker`: Defines the source of the version. Can be `FROM`, any supported _buildTool_ or an environment variable name.") | ||||
| 	cmd.Flags().StringVar(&stepConfig.FilePath, "filePath", os.Getenv("PIPER_filePath"), "Defines a custom path to the descriptor file. Build tool specific defaults are used (e.g. `maven: pom.xml`, `npm: package.json`, `mta: mta.yaml`).") | ||||
| 	cmd.Flags().StringVar(&stepConfig.GlobalSettingsFile, "globalSettingsFile", os.Getenv("PIPER_globalSettingsFile"), "Maven only - Path to the mvn settings file that should be used as global settings file.") | ||||
| 	cmd.Flags().BoolVar(&stepConfig.IncludeCommitID, "includeCommitId", true, "Defines if the automatically generated version (`versioningType: cloud`) should include the commit id hash.") | ||||
| @@ -178,6 +208,22 @@ func artifactPrepareVersionMetadata() config.StepData { | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{{Name: "gitUserName"}}, | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "customversionField", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:        "string", | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "customVersionSection", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
| 						Scope:       []string{"PARAMETERS", "STAGES", "STEPS"}, | ||||
| 						Type:        "string", | ||||
| 						Mandatory:   false, | ||||
| 						Aliases:     []config.Alias{}, | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "dockerVersionSource", | ||||
| 						ResourceRef: []config.ResourceReference{}, | ||||
|   | ||||
| @@ -205,7 +205,7 @@ func TestRunArtifactPrepareVersion(t *testing.T) { | ||||
| 		assert.Contains(t, cpe.artifactVersion, "1.2.3") | ||||
| 		assert.Equal(t, worktree.commitHash.String(), cpe.git.commitID) | ||||
|  | ||||
| 		assert.Equal(t, telemetry.CustomData{Custom1Label: "buildTool", Custom1: "maven"}, telemetryData) | ||||
| 		assert.Equal(t, telemetry.CustomData{Custom1Label: "buildTool", Custom1: "maven", Custom2Label: "filePath", Custom2: ""}, telemetryData) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("success case - cloud_noTag", func(t *testing.T) { | ||||
|   | ||||
							
								
								
									
										2
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.mod
									
									
									
									
									
								
							| @@ -15,10 +15,12 @@ require ( | ||||
| 	github.com/google/uuid v1.1.1 | ||||
| 	github.com/pkg/errors v0.9.1 | ||||
| 	github.com/sirupsen/logrus v1.4.2 | ||||
| 	github.com/smartystreets/goconvey v1.6.4 // indirect | ||||
| 	github.com/spf13/cobra v0.0.5 | ||||
| 	github.com/spf13/pflag v1.0.5 | ||||
| 	github.com/stretchr/testify v1.4.0 | ||||
| 	github.com/testcontainers/testcontainers-go v0.2.0 | ||||
| 	golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 | ||||
| 	gopkg.in/ini.v1 v1.55.0 | ||||
| 	gopkg.in/yaml.v2 v2.2.4 | ||||
| ) | ||||
|   | ||||
							
								
								
									
										11
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								go.sum
									
									
									
									
									
								
							| @@ -191,6 +191,8 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ | ||||
| github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= | ||||
| github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= | ||||
| github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= | ||||
| github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= | ||||
| github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | ||||
| github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= | ||||
| github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= | ||||
| github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= | ||||
| @@ -223,6 +225,8 @@ github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV | ||||
| github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= | ||||
| github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= | ||||
| github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= | ||||
| github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= | ||||
| github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= | ||||
| github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= | ||||
| github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY= | ||||
| github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= | ||||
| @@ -320,6 +324,10 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx | ||||
| github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= | ||||
| github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= | ||||
| github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= | ||||
| github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= | ||||
| github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= | ||||
| github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= | ||||
| github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= | ||||
| github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= | ||||
| github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= | ||||
| github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= | ||||
| @@ -469,6 +477,7 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3 | ||||
| golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= | ||||
| golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= | ||||
| golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= | ||||
| golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= | ||||
| golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= | ||||
| golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= | ||||
| golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= | ||||
| @@ -513,6 +522,8 @@ gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= | ||||
| gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= | ||||
| gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= | ||||
| gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= | ||||
| gopkg.in/ini.v1 v1.55.0 h1:E8yzL5unfpW3M6fz/eB7Cb5MQAYSZ7GKo4Qth+N2sgQ= | ||||
| gopkg.in/ini.v1 v1.55.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= | ||||
| gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= | ||||
| gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= | ||||
| gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= | ||||
|   | ||||
							
								
								
									
										130
									
								
								pkg/versioning/docker.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								pkg/versioning/docker.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,130 @@ | ||||
| package versioning | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
|  | ||||
| // Docker defines an artifact based on a Dockerfile | ||||
| type Docker struct { | ||||
| 	artifact      Artifact | ||||
| 	content       []byte | ||||
| 	execRunner    mavenExecRunner | ||||
| 	options       *Options | ||||
| 	path          string | ||||
| 	versionSource string | ||||
| 	readFile      func(string) ([]byte, error) | ||||
| 	writeFile     func(string, []byte, os.FileMode) error | ||||
| } | ||||
|  | ||||
| func (d *Docker) init() { | ||||
| 	if d.readFile == nil { | ||||
| 		d.readFile = ioutil.ReadFile | ||||
| 	} | ||||
|  | ||||
| 	if d.writeFile == nil { | ||||
| 		d.writeFile = ioutil.WriteFile | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (d *Docker) initDockerfile() { | ||||
| 	if len(d.path) == 0 { | ||||
| 		d.path = "Dockerfile" | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // VersioningScheme returns the relevant versioning scheme | ||||
| func (d *Docker) VersioningScheme() string { | ||||
| 	return "maven" | ||||
| } | ||||
|  | ||||
| // GetVersion returns the current version of the artifact | ||||
| func (d *Docker) GetVersion() (string, error) { | ||||
| 	d.init() | ||||
| 	var err error | ||||
|  | ||||
| 	switch d.versionSource { | ||||
| 	case "FROM": | ||||
| 		var err error | ||||
| 		d.initDockerfile() | ||||
| 		d.content, err = d.readFile(d.path) | ||||
| 		if err != nil { | ||||
| 			return "", errors.Wrapf(err, "failed to read file '%v'", d.path) | ||||
| 		} | ||||
| 		version := d.versionFromBaseImageTag() | ||||
| 		if len(version) == 0 { | ||||
| 			return "", fmt.Errorf("no version information available in FROM statement") | ||||
| 		} | ||||
| 		return version, nil | ||||
| 	case "custom", "dub", "golang", "maven", "mta", "npm", "pip", "sbt": | ||||
| 		d.artifact, err = GetArtifact(d.versionSource, d.path, d.options, d.execRunner) | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
| 		return d.artifact.GetVersion() | ||||
| 	default: | ||||
| 		d.initDockerfile() | ||||
| 		d.content, err = d.readFile(d.path) | ||||
| 		if err != nil { | ||||
| 			return "", errors.Wrapf(err, "failed to read file '%v'", d.path) | ||||
| 		} | ||||
| 		version := d.versionFromEnv(d.versionSource) | ||||
| 		if len(version) == 0 { | ||||
| 			return "", fmt.Errorf("no version information available in ENV '%v'", d.versionSource) | ||||
| 		} | ||||
| 		return version, nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // SetVersion updates the version of the artifact | ||||
| func (d *Docker) SetVersion(version string) error { | ||||
| 	d.init() | ||||
|  | ||||
| 	dir := "" | ||||
|  | ||||
| 	if d.artifact != nil { | ||||
| 		err := d.artifact.SetVersion(version) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		dir = filepath.Dir(d.path) | ||||
| 	} | ||||
|  | ||||
| 	err := d.writeFile(filepath.Join(dir, "VERSION"), []byte(version), 0700) | ||||
| 	if err != nil { | ||||
| 		return errors.Wrap(err, "failed to write file 'VERSION'") | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (d *Docker) versionFromEnv(env string) string { | ||||
| 	lines := strings.Split(string(d.content), "\n") | ||||
| 	for _, line := range lines { | ||||
| 		if strings.HasPrefix(line, "ENV") && strings.Fields(line)[1] == env { | ||||
| 			return strings.Fields(line)[2] | ||||
| 		} | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| func (d *Docker) versionFromBaseImageTag() string { | ||||
| 	lines := strings.Split(string(d.content), "\n") | ||||
| 	for _, line := range lines { | ||||
| 		if strings.HasPrefix(line, "FROM") { | ||||
| 			imageParts := strings.Split(line, ":") | ||||
| 			partsCount := len(imageParts) | ||||
| 			if partsCount == 1 { | ||||
| 				return "" | ||||
| 			} | ||||
| 			version := imageParts[partsCount-1] | ||||
| 			return strings.TrimSpace(version) | ||||
| 		} | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
							
								
								
									
										160
									
								
								pkg/versioning/docker_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										160
									
								
								pkg/versioning/docker_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,160 @@ | ||||
| package versioning | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| func TestDockerGetVersion(t *testing.T) { | ||||
| 	t.Run("success case - FROM", func(t *testing.T) { | ||||
| 		docker := Docker{ | ||||
| 			readFile:      func(filename string) ([]byte, error) { return []byte("FROM test:1.2.3"), nil }, | ||||
| 			versionSource: "FROM", | ||||
| 		} | ||||
| 		version, err := docker.GetVersion() | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, "1.2.3", version) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("error case - FROM failed", func(t *testing.T) { | ||||
| 		docker := Docker{ | ||||
| 			readFile:      func(filename string) ([]byte, error) { return []byte("FROM test"), nil }, | ||||
| 			versionSource: "FROM", | ||||
| 		} | ||||
| 		_, err := docker.GetVersion() | ||||
| 		assert.EqualError(t, err, "no version information available in FROM statement") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("error case - FROM read error", func(t *testing.T) { | ||||
| 		docker := Docker{ | ||||
| 			readFile:      func(filename string) ([]byte, error) { return []byte{}, fmt.Errorf("read error") }, | ||||
| 			versionSource: "FROM", | ||||
| 		} | ||||
| 		_, err := docker.GetVersion() | ||||
| 		assert.EqualError(t, err, "failed to read file 'Dockerfile': read error") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("success case - buildTool", func(t *testing.T) { | ||||
|  | ||||
| 		dir, err := ioutil.TempDir("", "") | ||||
| 		if err != nil { | ||||
| 			t.Fatal("Failed to create temporary directory") | ||||
| 		} | ||||
| 		// clean up tmp dir | ||||
| 		defer os.RemoveAll(dir) | ||||
| 		filePath := filepath.Join(dir, "package.json") | ||||
| 		err = ioutil.WriteFile(filePath, []byte(`{"version": "1.2.3"}`), 0700) | ||||
| 		if err != nil { | ||||
| 			t.Fatal("Failed to create test file") | ||||
| 		} | ||||
| 		docker := Docker{ | ||||
| 			path:          filePath, | ||||
| 			versionSource: "npm", | ||||
| 		} | ||||
| 		version, err := docker.GetVersion() | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, "1.2.3", version) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("success case - ENV", func(t *testing.T) { | ||||
| 		docker := Docker{ | ||||
| 			readFile:      func(filename string) ([]byte, error) { return []byte("FROM test:latest\n\nENV VERSION_ENV 1.2.3"), nil }, | ||||
| 			versionSource: "VERSION_ENV", | ||||
| 		} | ||||
| 		version, err := docker.GetVersion() | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, "1.2.3", version) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("error case - ENV failed", func(t *testing.T) { | ||||
| 		docker := Docker{ | ||||
| 			readFile:      func(filename string) ([]byte, error) { return []byte("FROM test:latest\n\nENV VERSION_ENV 1.2.3"), nil }, | ||||
| 			versionSource: "NOT_FOUND", | ||||
| 		} | ||||
| 		_, err := docker.GetVersion() | ||||
| 		assert.EqualError(t, err, "no version information available in ENV 'NOT_FOUND'") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("error case - ENV read error", func(t *testing.T) { | ||||
| 		docker := Docker{ | ||||
| 			readFile:      func(filename string) ([]byte, error) { return []byte{}, fmt.Errorf("read error") }, | ||||
| 			versionSource: "VERSION_ENV", | ||||
| 		} | ||||
| 		_, err := docker.GetVersion() | ||||
| 		assert.EqualError(t, err, "failed to read file 'Dockerfile': read error") | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestDockerSetVersion(t *testing.T) { | ||||
| 	t.Run("success case", func(t *testing.T) { | ||||
| 		var content []byte | ||||
| 		docker := Docker{ | ||||
| 			readFile:      func(filename string) ([]byte, error) { return []byte("FROM test:1.2.3"), nil }, | ||||
| 			writeFile:     func(filename string, filecontent []byte, mode os.FileMode) error { content = filecontent; return nil }, | ||||
| 			versionSource: "FROM", | ||||
| 		} | ||||
| 		err := docker.SetVersion("1.2.4") | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Contains(t, string(content), "1.2.4") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("error case", func(t *testing.T) { | ||||
| 		docker := Docker{ | ||||
| 			readFile:      func(filename string) ([]byte, error) { return []byte("FROM test:1.2.3"), nil }, | ||||
| 			writeFile:     func(filename string, filecontent []byte, mode os.FileMode) error { return fmt.Errorf("write error") }, | ||||
| 			versionSource: "FROM", | ||||
| 		} | ||||
| 		err := docker.SetVersion("1.2.4") | ||||
| 		assert.EqualError(t, err, "failed to write file 'VERSION': write error") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("success case - buildTool", func(t *testing.T) { | ||||
| 		dir, err := ioutil.TempDir("", "") | ||||
| 		if err != nil { | ||||
| 			t.Fatal("Failed to create temporary directory") | ||||
| 		} | ||||
| 		// clean up tmp dir | ||||
| 		defer os.RemoveAll(dir) | ||||
| 		filePath := filepath.Join(dir, "package.json") | ||||
| 		err = ioutil.WriteFile(filePath, []byte(`{"version": "1.2.3"}`), 0700) | ||||
| 		if err != nil { | ||||
| 			t.Fatal("Failed to create test file") | ||||
| 		} | ||||
| 		docker := Docker{ | ||||
| 			path:          filePath, | ||||
| 			versionSource: "npm", | ||||
| 		} | ||||
| 		_, err = docker.GetVersion() | ||||
| 		assert.NoError(t, err) | ||||
| 		err = docker.SetVersion("1.2.4") | ||||
| 		assert.NoError(t, err) | ||||
| 		packageJSON, err := ioutil.ReadFile(filePath) | ||||
| 		assert.Contains(t, string(packageJSON), `"version": "1.2.4"`) | ||||
| 		versionContent, err := ioutil.ReadFile(filepath.Join(dir, "VERSION")) | ||||
| 		assert.Equal(t, "1.2.4", string(versionContent)) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestVersionFromBaseImageTag(t *testing.T) { | ||||
| 	tt := []struct { | ||||
| 		docker   *Docker | ||||
| 		expected string | ||||
| 	}{ | ||||
| 		{docker: &Docker{content: []byte("")}, expected: ""}, | ||||
| 		{docker: &Docker{content: []byte("FROM test")}, expected: ""}, | ||||
| 		//{docker: &Docker{content: []byte("FROM test:latest")}, expected: ""}, | ||||
| 		{docker: &Docker{content: []byte("FROM test:1.2.3")}, expected: "1.2.3"}, | ||||
| 		{docker: &Docker{content: []byte("#COMMENT\nFROM test:1.2.3")}, expected: "1.2.3"}, | ||||
| 		//{docker: &Docker{content: []byte("FROM my.registry:55555/test")}, expected: ""}, | ||||
| 		//{docker: &Docker{content: []byte("FROM my.registry:55555/test:latest")}, expected: ""}, | ||||
| 		{docker: &Docker{content: []byte("FROM my.registry:55555/test:1.2.3")}, expected: "1.2.3"}, | ||||
| 	} | ||||
| 	for _, test := range tt { | ||||
| 		assert.Equal(t, test.expected, test.docker.versionFromBaseImageTag()) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										83
									
								
								pkg/versioning/inifile.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								pkg/versioning/inifile.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,83 @@ | ||||
| package versioning | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
|  | ||||
| 	"github.com/pkg/errors" | ||||
| 	"gopkg.in/ini.v1" | ||||
| ) | ||||
|  | ||||
| // INIfile defines an artifact using a json file for versioning | ||||
| type INIfile struct { | ||||
| 	path           string | ||||
| 	content        *ini.File | ||||
| 	versionSection string | ||||
| 	versionField   string | ||||
| 	readFile       func(string) ([]byte, error) | ||||
| 	writeFile      func(string, []byte, os.FileMode) error | ||||
| } | ||||
|  | ||||
| func (i *INIfile) init() error { | ||||
| 	if len(i.versionField) == 0 { | ||||
| 		i.versionField = "version" | ||||
| 	} | ||||
| 	if i.readFile == nil { | ||||
| 		i.readFile = ioutil.ReadFile | ||||
| 	} | ||||
| 	if i.writeFile == nil { | ||||
| 		i.writeFile = ioutil.WriteFile | ||||
| 	} | ||||
| 	if i.content == nil { | ||||
| 		conf, err := i.readFile(i.path) | ||||
| 		if err != nil { | ||||
| 			return errors.Wrapf(err, "failed to read file '%v'", i.path) | ||||
| 		} | ||||
| 		i.content, err = ini.Load(conf) | ||||
| 		if err != nil { | ||||
| 			return errors.Wrapf(err, "failed to load content from file '%v'", i.path) | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // VersioningScheme returns the relevant versioning scheme | ||||
| func (i *INIfile) VersioningScheme() string { | ||||
| 	return "semver2" | ||||
| } | ||||
|  | ||||
| // GetVersion returns the current version of the artifact with a ini-file-based build descriptor | ||||
| func (i *INIfile) GetVersion() (string, error) { | ||||
| 	if i.content == nil { | ||||
| 		err := i.init() | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
| 	} | ||||
| 	section := i.content.Section(i.versionSection) | ||||
| 	if section.HasKey(i.versionField) { | ||||
| 		return section.Key(i.versionField).String(), nil | ||||
| 	} | ||||
| 	return "", fmt.Errorf("field '%v' not found in section '%v'", i.versionField, i.versionSection) | ||||
| } | ||||
|  | ||||
| // SetVersion updates the version of the artifact with a ini-file-based build descriptor | ||||
| func (i *INIfile) SetVersion(version string) error { | ||||
| 	if i.content == nil { | ||||
| 		err := i.init() | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	section := i.content.Section(i.versionSection) | ||||
| 	section.Key(i.versionField).SetValue(version) | ||||
| 	var buf bytes.Buffer | ||||
| 	i.content.WriteTo(&buf) | ||||
| 	err := i.writeFile(i.path, buf.Bytes(), 0700) | ||||
| 	if err != nil { | ||||
| 		return errors.Wrapf(err, "failed to write file '%v'", i.path) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										91
									
								
								pkg/versioning/inifile_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								pkg/versioning/inifile_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,91 @@ | ||||
| package versioning | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| func TestINIfileGetVersion(t *testing.T) { | ||||
| 	t.Run("success case", func(t *testing.T) { | ||||
| 		inifile := INIfile{ | ||||
| 			path:           "my.cfg", | ||||
| 			versionSection: "test", | ||||
| 			readFile:       func(filename string) ([]byte, error) { return []byte("[test]\nversion = 1.2.3 "), nil }, | ||||
| 		} | ||||
| 		version, err := inifile.GetVersion() | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, "1.2.3", version) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("error case - read error", func(t *testing.T) { | ||||
| 		inifile := INIfile{ | ||||
| 			path:     "my.cfg", | ||||
| 			readFile: func(filename string) ([]byte, error) { return []byte{}, fmt.Errorf("read error") }, | ||||
| 		} | ||||
| 		_, err := inifile.GetVersion() | ||||
| 		assert.EqualError(t, err, "failed to read file 'my.cfg': read error") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("error case - load error", func(t *testing.T) { | ||||
| 		inifile := INIfile{ | ||||
| 			path:     "my.cfg", | ||||
| 			readFile: func(filename string) ([]byte, error) { return []byte("1.2.3"), nil }, | ||||
| 		} | ||||
| 		_, err := inifile.GetVersion() | ||||
| 		assert.EqualError(t, err, "failed to load content from file 'my.cfg': key-value delimiter not found: 1.2.3") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("error case - field not found", func(t *testing.T) { | ||||
| 		inifile := INIfile{ | ||||
| 			path:     "my.cfg", | ||||
| 			readFile: func(filename string) ([]byte, error) { return []byte("theversion = 1.2.3"), nil }, | ||||
| 		} | ||||
| 		_, err := inifile.GetVersion() | ||||
| 		assert.EqualError(t, err, "field 'version' not found in section ''") | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestINIfileSetVersion(t *testing.T) { | ||||
| 	t.Run("success case - flat", func(t *testing.T) { | ||||
| 		var content []byte | ||||
| 		inifile := INIfile{ | ||||
| 			path:         "my.cfg", | ||||
| 			versionField: "theversion", | ||||
| 			readFile:     func(filename string) ([]byte, error) { return []byte("theversion = 1.2.3"), nil }, | ||||
| 			writeFile:    func(filename string, filecontent []byte, mode os.FileMode) error { content = filecontent; return nil }, | ||||
| 		} | ||||
| 		err := inifile.SetVersion("1.2.4") | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Contains(t, string(content), "theversion = 1.2.4") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("success case - section", func(t *testing.T) { | ||||
| 		var content []byte | ||||
| 		inifile := INIfile{ | ||||
| 			path:           "my.cfg", | ||||
| 			versionField:   "theversion", | ||||
| 			versionSection: "test", | ||||
| 			readFile:       func(filename string) ([]byte, error) { return []byte("[test]\ntheversion = 1.2.3"), nil }, | ||||
| 			writeFile:      func(filename string, filecontent []byte, mode os.FileMode) error { content = filecontent; return nil }, | ||||
| 		} | ||||
| 		err := inifile.SetVersion("1.2.4") | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Contains(t, string(content), "[test]") | ||||
| 		assert.Contains(t, string(content), "1.2.4") | ||||
| 		assert.NotContains(t, string(content), "1.2.3") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("error case", func(t *testing.T) { | ||||
| 		inifile := INIfile{ | ||||
| 			path:         "my.cfg", | ||||
| 			versionField: "theversion", | ||||
| 			readFile:     func(filename string) ([]byte, error) { return []byte("theversion = 1.2.3"), nil }, | ||||
| 			writeFile:    func(filename string, filecontent []byte, mode os.FileMode) error { return fmt.Errorf("write error") }, | ||||
| 		} | ||||
| 		err := inifile.SetVersion("1.2.4") | ||||
| 		assert.EqualError(t, err, "failed to write file 'my.cfg': write error") | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										78
									
								
								pkg/versioning/jsonfile.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								pkg/versioning/jsonfile.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,78 @@ | ||||
| package versioning | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
|  | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
|  | ||||
| // JSONfile defines an artifact using a json file for versioning | ||||
| type JSONfile struct { | ||||
| 	path         string | ||||
| 	content      map[string]interface{} | ||||
| 	versionField string | ||||
| 	readFile     func(string) ([]byte, error) | ||||
| 	writeFile    func(string, []byte, os.FileMode) error | ||||
| } | ||||
|  | ||||
| func (j *JSONfile) init() { | ||||
| 	if len(j.versionField) == 0 { | ||||
| 		j.versionField = "version" | ||||
| 	} | ||||
| 	if j.readFile == nil { | ||||
| 		j.readFile = ioutil.ReadFile | ||||
| 	} | ||||
|  | ||||
| 	if j.writeFile == nil { | ||||
| 		j.writeFile = ioutil.WriteFile | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // VersioningScheme returns the relevant versioning scheme | ||||
| func (j *JSONfile) VersioningScheme() string { | ||||
| 	return "semver2" | ||||
| } | ||||
|  | ||||
| // GetVersion returns the current version of the artifact with a JSON-based build descriptor | ||||
| func (j *JSONfile) GetVersion() (string, error) { | ||||
| 	j.init() | ||||
|  | ||||
| 	content, err := j.readFile(j.path) | ||||
| 	if err != nil { | ||||
| 		return "", errors.Wrapf(err, "failed to read file '%v'", j.path) | ||||
| 	} | ||||
|  | ||||
| 	err = json.Unmarshal(content, &j.content) | ||||
| 	if err != nil { | ||||
| 		return "", errors.Wrapf(err, "failed to read json content of file '%v'", j.content) | ||||
| 	} | ||||
|  | ||||
| 	return fmt.Sprint(j.content[j.versionField]), nil | ||||
| } | ||||
|  | ||||
| // SetVersion updates the version of the artifact with a JSON-based build descriptor | ||||
| func (j *JSONfile) SetVersion(version string) error { | ||||
| 	j.init() | ||||
|  | ||||
| 	if j.content == nil { | ||||
| 		_, err := j.GetVersion() | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	j.content[j.versionField] = version | ||||
|  | ||||
| 	content, err := json.MarshalIndent(j.content, "", "  ") | ||||
| 	if err != nil { | ||||
| 		return errors.Wrapf(err, "failed to create json content for '%v'", j.path) | ||||
| 	} | ||||
| 	err = j.writeFile(j.path, content, 0700) | ||||
| 	if err != nil { | ||||
| 		return errors.Wrapf(err, "failed to write file '%v'", j.path) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										57
									
								
								pkg/versioning/jsonfile_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								pkg/versioning/jsonfile_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | ||||
| package versioning | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| func TestJSONfileGetVersion(t *testing.T) { | ||||
| 	t.Run("success case", func(t *testing.T) { | ||||
| 		jsonfile := JSONfile{ | ||||
| 			path:     "my.json", | ||||
| 			readFile: func(filename string) ([]byte, error) { return []byte(`{"version": "1.2.3"}`), nil }, | ||||
| 		} | ||||
| 		version, err := jsonfile.GetVersion() | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, "1.2.3", version) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("error case", func(t *testing.T) { | ||||
| 		jsonfile := JSONfile{ | ||||
| 			path:         "my.json", | ||||
| 			versionField: "theversion", | ||||
| 			readFile:     func(filename string) ([]byte, error) { return []byte{}, fmt.Errorf("read error") }, | ||||
| 		} | ||||
| 		_, err := jsonfile.GetVersion() | ||||
| 		assert.EqualError(t, err, "failed to read file 'my.json': read error") | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestJSONfileSetVersion(t *testing.T) { | ||||
| 	t.Run("success case", func(t *testing.T) { | ||||
| 		var content []byte | ||||
| 		jsonfile := JSONfile{ | ||||
| 			path:         "my.json", | ||||
| 			versionField: "theversion", | ||||
| 			readFile:     func(filename string) ([]byte, error) { return []byte(`{"theversion": "1.2.3"}`), nil }, | ||||
| 			writeFile:    func(filename string, filecontent []byte, mode os.FileMode) error { content = filecontent; return nil }, | ||||
| 		} | ||||
| 		err := jsonfile.SetVersion("1.2.4") | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Contains(t, string(content), `"theversion": "1.2.4"`) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("error case", func(t *testing.T) { | ||||
| 		jsonfile := JSONfile{ | ||||
| 			path:         "my.json", | ||||
| 			versionField: "theversion", | ||||
| 			readFile:     func(filename string) ([]byte, error) { return []byte(`{"theversion": "1.2.3"}`), nil }, | ||||
| 			writeFile:    func(filename string, filecontent []byte, mode os.FileMode) error { return fmt.Errorf("write error") }, | ||||
| 		} | ||||
| 		err := jsonfile.SetVersion("1.2.4") | ||||
| 		assert.EqualError(t, err, "failed to write file 'my.json': write error") | ||||
| 	}) | ||||
| } | ||||
| @@ -21,37 +21,36 @@ type mavenRunner interface { | ||||
| 	Evaluate(string, string, mavenExecRunner) (string, error) | ||||
| } | ||||
|  | ||||
| // Maven ... | ||||
| // Maven defines a maven artifact used for versioning | ||||
| type Maven struct { | ||||
| 	PomPath             string | ||||
| 	Runner              mavenRunner | ||||
| 	ExecRunner          mavenExecRunner | ||||
| 	ProjectSettingsFile string | ||||
| 	GlobalSettingsFile  string | ||||
| 	M2Path              string | ||||
| 	pomPath             string | ||||
| 	runner              mavenRunner | ||||
| 	execRunner          mavenExecRunner | ||||
| 	projectSettingsFile string | ||||
| 	globalSettingsFile  string | ||||
| 	m2Path              string | ||||
| } | ||||
|  | ||||
| // InitBuildDescriptor ... | ||||
| func (m *Maven) init() { | ||||
| 	if len(m.PomPath) == 0 { | ||||
| 		m.PomPath = "pom.xml" | ||||
| 	if len(m.pomPath) == 0 { | ||||
| 		m.pomPath = "pom.xml" | ||||
| 	} | ||||
|  | ||||
| 	if m.ExecRunner == nil { | ||||
| 		m.ExecRunner = &command.Command{} | ||||
| 	if m.execRunner == nil { | ||||
| 		m.execRunner = &command.Command{} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // VersioningScheme ... | ||||
| // VersioningScheme returns the relevant versioning scheme | ||||
| func (m *Maven) VersioningScheme() string { | ||||
| 	return "maven" | ||||
| } | ||||
|  | ||||
| // GetVersion ... | ||||
| // GetVersion returns the current version of the artifact | ||||
| func (m *Maven) GetVersion() (string, error) { | ||||
| 	m.init() | ||||
|  | ||||
| 	version, err := m.Runner.Evaluate(m.PomPath, "project.version", m.ExecRunner) | ||||
| 	version, err := m.runner.Evaluate(m.pomPath, "project.version", m.execRunner) | ||||
| 	if err != nil { | ||||
| 		return "", errors.Wrap(err, "Maven - getting version failed") | ||||
| 	} | ||||
| @@ -59,19 +58,19 @@ func (m *Maven) GetVersion() (string, error) { | ||||
| 	return version, nil | ||||
| } | ||||
|  | ||||
| // SetVersion ... | ||||
| // SetVersion updates the version of the artifact | ||||
| func (m *Maven) SetVersion(version string) error { | ||||
| 	m.init() | ||||
|  | ||||
| 	groupID, err := m.Runner.Evaluate(m.PomPath, "project.groupId", m.ExecRunner) | ||||
| 	groupID, err := m.runner.Evaluate(m.pomPath, "project.groupId", m.execRunner) | ||||
| 	if err != nil { | ||||
| 		return errors.Wrap(err, "Maven - getting groupId failed") | ||||
| 	} | ||||
| 	opts := maven.ExecuteOptions{ | ||||
| 		PomPath:             m.PomPath, | ||||
| 		ProjectSettingsFile: m.ProjectSettingsFile, | ||||
| 		GlobalSettingsFile:  m.GlobalSettingsFile, | ||||
| 		M2Path:              m.M2Path, | ||||
| 		PomPath:             m.pomPath, | ||||
| 		ProjectSettingsFile: m.projectSettingsFile, | ||||
| 		GlobalSettingsFile:  m.globalSettingsFile, | ||||
| 		M2Path:              m.m2Path, | ||||
| 		Goals:               []string{"org.codehaus.mojo:versions-maven-plugin:2.7:set"}, | ||||
| 		Defines: []string{ | ||||
| 			fmt.Sprintf("-DnewVersion=%v", version), | ||||
| @@ -81,7 +80,7 @@ func (m *Maven) SetVersion(version string) error { | ||||
| 			"-DgenerateBackupPoms=false", | ||||
| 		}, | ||||
| 	} | ||||
| 	_, err = m.Runner.Execute(&opts, m.ExecRunner) | ||||
| 	_, err = m.runner.Execute(&opts, m.execRunner) | ||||
| 	if err != nil { | ||||
| 		return errors.Wrapf(err, "Maven - setting version %v failed", version) | ||||
| 	} | ||||
|   | ||||
| @@ -43,8 +43,8 @@ func TestMavenGetVersion(t *testing.T) { | ||||
| 			stdout: "1.2.3", | ||||
| 		} | ||||
| 		mvn := &Maven{ | ||||
| 			Runner:  &runner, | ||||
| 			PomPath: "path/to/pom.xml", | ||||
| 			runner:  &runner, | ||||
| 			pomPath: "path/to/pom.xml", | ||||
| 		} | ||||
| 		version, err := mvn.GetVersion() | ||||
| 		assert.NoError(t, err) | ||||
| @@ -59,7 +59,7 @@ func TestMavenGetVersion(t *testing.T) { | ||||
| 			evaluateErrorString: "maven eval failed", | ||||
| 		} | ||||
| 		mvn := &Maven{ | ||||
| 			Runner: &runner, | ||||
| 			runner: &runner, | ||||
| 		} | ||||
| 		version, err := mvn.GetVersion() | ||||
| 		assert.EqualError(t, err, "Maven - getting version failed: maven eval failed") | ||||
| @@ -74,11 +74,11 @@ func TestMavenSetVersion(t *testing.T) { | ||||
| 			stdout: "testGroup", | ||||
| 		} | ||||
| 		mvn := &Maven{ | ||||
| 			Runner:              &runner, | ||||
| 			PomPath:             "path/to/pom.xml", | ||||
| 			ProjectSettingsFile: "project-settings.xml", | ||||
| 			GlobalSettingsFile:  "global-settings.xml", | ||||
| 			M2Path:              "m2/path", | ||||
| 			runner:              &runner, | ||||
| 			pomPath:             "path/to/pom.xml", | ||||
| 			projectSettingsFile: "project-settings.xml", | ||||
| 			globalSettingsFile:  "global-settings.xml", | ||||
| 			m2Path:              "m2/path", | ||||
| 		} | ||||
| 		expectedOptions := maven.ExecuteOptions{ | ||||
| 			PomPath:             "path/to/pom.xml", | ||||
| @@ -99,8 +99,8 @@ func TestMavenSetVersion(t *testing.T) { | ||||
| 			evaluateErrorString: "maven eval failed", | ||||
| 		} | ||||
| 		mvn := &Maven{ | ||||
| 			Runner:  &runner, | ||||
| 			PomPath: "path/to/pom.xml", | ||||
| 			runner:  &runner, | ||||
| 			pomPath: "path/to/pom.xml", | ||||
| 		} | ||||
| 		err := mvn.SetVersion("1.2.4") | ||||
| 		assert.EqualError(t, err, "Maven - getting groupId failed: maven eval failed") | ||||
| @@ -112,8 +112,8 @@ func TestMavenSetVersion(t *testing.T) { | ||||
| 			executeErrorString: "maven exec failed", | ||||
| 		} | ||||
| 		mvn := &Maven{ | ||||
| 			Runner:  &runner, | ||||
| 			PomPath: "path/to/pom.xml", | ||||
| 			runner:  &runner, | ||||
| 			pomPath: "path/to/pom.xml", | ||||
| 		} | ||||
| 		err := mvn.SetVersion("1.2.4") | ||||
| 		assert.EqualError(t, err, "Maven - setting version 1.2.4 failed: maven exec failed") | ||||
|   | ||||
| @@ -1,78 +0,0 @@ | ||||
| package versioning | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
|  | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
|  | ||||
| // Npm ... | ||||
| type Npm struct { | ||||
| 	PackageJSONPath    string | ||||
| 	PackageJSONContent map[string]interface{} | ||||
| 	ReadFile           func(string) ([]byte, error) | ||||
| 	WriteFile          func(string, []byte, os.FileMode) error | ||||
| } | ||||
|  | ||||
| // InitBuildDescriptor ... | ||||
| func (n *Npm) init() { | ||||
| 	if len(n.PackageJSONPath) == 0 { | ||||
| 		n.PackageJSONPath = "package.json" | ||||
| 	} | ||||
| 	if n.ReadFile == nil { | ||||
| 		n.ReadFile = ioutil.ReadFile | ||||
| 	} | ||||
|  | ||||
| 	if n.WriteFile == nil { | ||||
| 		n.WriteFile = ioutil.WriteFile | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // VersioningScheme ... | ||||
| func (n *Npm) VersioningScheme() string { | ||||
| 	return "semver2" | ||||
| } | ||||
|  | ||||
| // GetVersion ... | ||||
| func (n *Npm) GetVersion() (string, error) { | ||||
| 	n.init() | ||||
|  | ||||
| 	content, err := n.ReadFile(n.PackageJSONPath) | ||||
| 	if err != nil { | ||||
| 		return "", errors.Wrapf(err, "failed to read file '%v'", n.PackageJSONPath) | ||||
| 	} | ||||
|  | ||||
| 	err = json.Unmarshal(content, &n.PackageJSONContent) | ||||
| 	if err != nil { | ||||
| 		return "", errors.Wrap(err, "failed to read package.json content") | ||||
| 	} | ||||
|  | ||||
| 	return fmt.Sprint(n.PackageJSONContent["version"]), nil | ||||
| } | ||||
|  | ||||
| // SetVersion ... | ||||
| func (n *Npm) SetVersion(version string) error { | ||||
| 	n.init() | ||||
|  | ||||
| 	if n.PackageJSONContent == nil { | ||||
| 		_, err := n.GetVersion() | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	n.PackageJSONContent["version"] = version | ||||
|  | ||||
| 	content, err := json.MarshalIndent(n.PackageJSONContent, "", "  ") | ||||
| 	if err != nil { | ||||
| 		return errors.Wrap(err, "failed to create json content for package.json") | ||||
| 	} | ||||
| 	err = n.WriteFile(n.PackageJSONPath, content, 0700) | ||||
| 	if err != nil { | ||||
| 		return errors.Wrapf(err, "failed to write file '%v'", n.PackageJSONPath) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
| @@ -1,73 +0,0 @@ | ||||
| package versioning | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| func TestInit(t *testing.T) { | ||||
| 	t.Run("default", func(t *testing.T) { | ||||
| 		npm := Npm{} | ||||
| 		npm.init() | ||||
| 		assert.Equal(t, "package.json", npm.PackageJSONPath) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("no default", func(t *testing.T) { | ||||
| 		npm := Npm{PackageJSONPath: "my/package.json"} | ||||
| 		npm.init() | ||||
| 		assert.Equal(t, "my/package.json", npm.PackageJSONPath) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestVersioningScheme(t *testing.T) { | ||||
| 	npm := Npm{} | ||||
| 	assert.Equal(t, "semver2", npm.VersioningScheme()) | ||||
| } | ||||
|  | ||||
| func TestGetVersion(t *testing.T) { | ||||
| 	t.Run("success case", func(t *testing.T) { | ||||
| 		npm := Npm{ | ||||
| 			PackageJSONPath: "my/package.json", | ||||
| 			ReadFile:        func(filename string) ([]byte, error) { return []byte(`{"name": "test","version": "1.2.3"}`), nil }, | ||||
| 		} | ||||
| 		version, err := npm.GetVersion() | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, "1.2.3", version) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("error case", func(t *testing.T) { | ||||
| 		npm := Npm{ | ||||
| 			PackageJSONPath: "my/package.json", | ||||
| 			ReadFile:        func(filename string) ([]byte, error) { return []byte{}, fmt.Errorf("read error") }, | ||||
| 		} | ||||
| 		_, err := npm.GetVersion() | ||||
| 		assert.EqualError(t, err, "failed to read file 'my/package.json': read error") | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestSetVersion(t *testing.T) { | ||||
| 	t.Run("success case", func(t *testing.T) { | ||||
| 		var content []byte | ||||
| 		npm := Npm{ | ||||
| 			PackageJSONPath: "my/package.json", | ||||
| 			ReadFile:        func(filename string) ([]byte, error) { return []byte(`{"name": "test","version": "1.2.3"}`), nil }, | ||||
| 			WriteFile:       func(filename string, filecontent []byte, mode os.FileMode) error { content = filecontent; return nil }, | ||||
| 		} | ||||
| 		err := npm.SetVersion("1.2.4") | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Contains(t, string(content), "1.2.4") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("error case", func(t *testing.T) { | ||||
| 		npm := Npm{ | ||||
| 			PackageJSONPath: "my/package.json", | ||||
| 			ReadFile:        func(filename string) ([]byte, error) { return []byte(`{"name": "test","version": "1.2.3"}`), nil }, | ||||
| 			WriteFile:       func(filename string, filecontent []byte, mode os.FileMode) error { return fmt.Errorf("write error") }, | ||||
| 		} | ||||
| 		err := npm.SetVersion("1.2.4") | ||||
| 		assert.EqualError(t, err, "failed to write file 'my/package.json': write error") | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										62
									
								
								pkg/versioning/versionfile.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								pkg/versioning/versionfile.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | ||||
| package versioning | ||||
|  | ||||
| import ( | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
|  | ||||
| // Versionfile defines an artifact containing the version in a file, e.g. VERSION | ||||
| type Versionfile struct { | ||||
| 	path             string | ||||
| 	readFile         func(string) ([]byte, error) | ||||
| 	writeFile        func(string, []byte, os.FileMode) error | ||||
| 	versioningScheme string | ||||
| } | ||||
|  | ||||
| func (v *Versionfile) init() { | ||||
| 	if len(v.path) == 0 { | ||||
| 		v.path = "VERSION" | ||||
| 	} | ||||
| 	if v.readFile == nil { | ||||
| 		v.readFile = ioutil.ReadFile | ||||
| 	} | ||||
|  | ||||
| 	if v.writeFile == nil { | ||||
| 		v.writeFile = ioutil.WriteFile | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // VersioningScheme returns the relevant versioning scheme | ||||
| func (v *Versionfile) VersioningScheme() string { | ||||
| 	if len(v.versioningScheme) == 0 { | ||||
| 		return "semver2" | ||||
| 	} | ||||
| 	return v.versioningScheme | ||||
| } | ||||
|  | ||||
| // GetVersion returns the current version of the artifact | ||||
| func (v *Versionfile) GetVersion() (string, error) { | ||||
| 	v.init() | ||||
|  | ||||
| 	content, err := v.readFile(v.path) | ||||
| 	if err != nil { | ||||
| 		return "", errors.Wrapf(err, "failed to read file '%v'", v.path) | ||||
| 	} | ||||
|  | ||||
| 	return strings.TrimSpace(string(content)), nil | ||||
| } | ||||
|  | ||||
| // SetVersion updates the version of the artifact | ||||
| func (v *Versionfile) SetVersion(version string) error { | ||||
| 	v.init() | ||||
|  | ||||
| 	err := v.writeFile(v.path, []byte(version), 0700) | ||||
| 	if err != nil { | ||||
| 		return errors.Wrapf(err, "failed to write file '%v'", v.path) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										83
									
								
								pkg/versioning/versionfile_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								pkg/versioning/versionfile_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,83 @@ | ||||
| package versioning | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| func TestVersionfileInit(t *testing.T) { | ||||
| 	t.Run("default", func(t *testing.T) { | ||||
| 		versionfile := Versionfile{} | ||||
| 		versionfile.init() | ||||
| 		assert.Equal(t, "VERSION", versionfile.path) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("no default", func(t *testing.T) { | ||||
| 		versionfile := Versionfile{path: "my/VERSION"} | ||||
| 		versionfile.init() | ||||
| 		assert.Equal(t, "my/VERSION", versionfile.path) | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestVersionfileVersioningScheme(t *testing.T) { | ||||
| 	versionfile := Versionfile{} | ||||
| 	assert.Equal(t, "semver2", versionfile.VersioningScheme()) | ||||
| } | ||||
|  | ||||
| func TestVersionfileGetVersion(t *testing.T) { | ||||
| 	t.Run("success case", func(t *testing.T) { | ||||
| 		versionfile := Versionfile{ | ||||
| 			path:     "my/VERSION", | ||||
| 			readFile: func(filename string) ([]byte, error) { return []byte("1.2.3"), nil }, | ||||
| 		} | ||||
| 		version, err := versionfile.GetVersion() | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, "1.2.3", version) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("success case - trimming", func(t *testing.T) { | ||||
| 		versionfile := Versionfile{ | ||||
| 			path:     "my/VERSION", | ||||
| 			readFile: func(filename string) ([]byte, error) { return []byte("1.2.3 \n"), nil }, | ||||
| 		} | ||||
| 		version, err := versionfile.GetVersion() | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, "1.2.3", version) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("error case", func(t *testing.T) { | ||||
| 		versionfile := Versionfile{ | ||||
| 			path:     "my/VERSION", | ||||
| 			readFile: func(filename string) ([]byte, error) { return []byte{}, fmt.Errorf("read error") }, | ||||
| 		} | ||||
| 		_, err := versionfile.GetVersion() | ||||
| 		assert.EqualError(t, err, "failed to read file 'my/VERSION': read error") | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestVersionfileSetVersion(t *testing.T) { | ||||
| 	t.Run("success case", func(t *testing.T) { | ||||
| 		var content []byte | ||||
| 		versionfile := Versionfile{ | ||||
| 			path:      "my/VERSION", | ||||
| 			readFile:  func(filename string) ([]byte, error) { return []byte("1.2.3"), nil }, | ||||
| 			writeFile: func(filename string, filecontent []byte, mode os.FileMode) error { content = filecontent; return nil }, | ||||
| 		} | ||||
| 		err := versionfile.SetVersion("1.2.4") | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Contains(t, string(content), "1.2.4") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("error case", func(t *testing.T) { | ||||
| 		versionfile := Versionfile{ | ||||
| 			path:      "my/VERSION", | ||||
| 			readFile:  func(filename string) ([]byte, error) { return []byte("1.2.3"), nil }, | ||||
| 			writeFile: func(filename string, filecontent []byte, mode os.FileMode) error { return fmt.Errorf("write error") }, | ||||
| 		} | ||||
| 		err := versionfile.SetVersion("1.2.4") | ||||
| 		assert.EqualError(t, err, "failed to write file 'my/VERSION': write error") | ||||
| 	}) | ||||
| } | ||||
| @@ -2,22 +2,28 @@ package versioning | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"path/filepath" | ||||
|  | ||||
| 	"github.com/SAP/jenkins-library/pkg/piperutils" | ||||
|  | ||||
| 	"github.com/SAP/jenkins-library/pkg/maven" | ||||
| ) | ||||
|  | ||||
| // Artifact ... | ||||
| // Artifact defines the versioning operations for various build tools | ||||
| type Artifact interface { | ||||
| 	VersioningScheme() string | ||||
| 	GetVersion() (string, error) | ||||
| 	SetVersion(string) error | ||||
| } | ||||
|  | ||||
| // Options ... | ||||
| // Options define build tool specific settings in order to properly retrieve e.g. the version of an artifact | ||||
| type Options struct { | ||||
| 	ProjectSettingsFile string | ||||
| 	GlobalSettingsFile  string | ||||
| 	M2Path              string | ||||
| 	VersionSource       string | ||||
| 	VersionSection      string | ||||
| 	VersionField        string | ||||
| } | ||||
|  | ||||
| type mvnRunner struct{} | ||||
| @@ -29,22 +35,94 @@ func (m *mvnRunner) Evaluate(pomFile, expression string, execRunner mavenExecRun | ||||
| 	return maven.Evaluate(pomFile, expression, execRunner) | ||||
| } | ||||
|  | ||||
| // GetArtifact ... | ||||
| var fileExists func(string) (bool, error) | ||||
|  | ||||
| // GetArtifact returns the build tool specific implementation for retrieving version, etc. of an artifact | ||||
| func GetArtifact(buildTool, buildDescriptorFilePath string, opts *Options, execRunner mavenExecRunner) (Artifact, error) { | ||||
| 	var artifact Artifact | ||||
| 	if fileExists == nil { | ||||
| 		fileExists = piperutils.FileExists | ||||
| 	} | ||||
| 	switch buildTool { | ||||
| 	case "custom": | ||||
| 		var err error | ||||
| 		artifact, err = customArtifact(buildDescriptorFilePath, opts.VersionField, opts.VersionSection) | ||||
| 		if err != nil { | ||||
| 			return artifact, err | ||||
| 		} | ||||
| 	case "docker": | ||||
| 		artifact = &Docker{ | ||||
| 			execRunner:    execRunner, | ||||
| 			options:       opts, | ||||
| 			path:          buildDescriptorFilePath, | ||||
| 			versionSource: opts.VersionSource, | ||||
| 		} | ||||
| 	case "dub": | ||||
| 		if len(buildDescriptorFilePath) == 0 { | ||||
| 			buildDescriptorFilePath = "dub.json" | ||||
| 		} | ||||
| 		artifact = &JSONfile{ | ||||
| 			path:         buildDescriptorFilePath, | ||||
| 			versionField: "version", | ||||
| 		} | ||||
| 	case "golang": | ||||
| 		if len(buildDescriptorFilePath) == 0 { | ||||
| 			var err error | ||||
| 			buildDescriptorFilePath, err = searchDescriptor([]string{"VERSION", "version.txt"}, fileExists) | ||||
| 			if err != nil { | ||||
| 				return artifact, err | ||||
| 			} | ||||
| 		} | ||||
| 		artifact = &Versionfile{ | ||||
| 			path: buildDescriptorFilePath, | ||||
| 		} | ||||
| 	case "maven": | ||||
| 		if len(buildDescriptorFilePath) == 0 { | ||||
| 			buildDescriptorFilePath = "pom.xml" | ||||
| 		} | ||||
| 		artifact = &Maven{ | ||||
| 			Runner:              &mvnRunner{}, | ||||
| 			ExecRunner:          execRunner, | ||||
| 			PomPath:             buildDescriptorFilePath, | ||||
| 			ProjectSettingsFile: opts.ProjectSettingsFile, | ||||
| 			GlobalSettingsFile:  opts.GlobalSettingsFile, | ||||
| 			M2Path:              opts.M2Path, | ||||
| 			runner:              &mvnRunner{}, | ||||
| 			execRunner:          execRunner, | ||||
| 			pomPath:             buildDescriptorFilePath, | ||||
| 			projectSettingsFile: opts.ProjectSettingsFile, | ||||
| 			globalSettingsFile:  opts.GlobalSettingsFile, | ||||
| 			m2Path:              opts.M2Path, | ||||
| 		} | ||||
| 	case "mta": | ||||
| 		if len(buildDescriptorFilePath) == 0 { | ||||
| 			buildDescriptorFilePath = "mta.yaml" | ||||
| 		} | ||||
| 		artifact = &YAMLfile{ | ||||
| 			path:         buildDescriptorFilePath, | ||||
| 			versionField: "version", | ||||
| 		} | ||||
| 	case "npm": | ||||
| 		artifact = &Npm{ | ||||
| 			PackageJSONPath: buildDescriptorFilePath, | ||||
| 		if len(buildDescriptorFilePath) == 0 { | ||||
| 			buildDescriptorFilePath = "package.json" | ||||
| 		} | ||||
| 		artifact = &JSONfile{ | ||||
| 			path:         buildDescriptorFilePath, | ||||
| 			versionField: "version", | ||||
| 		} | ||||
| 	case "pip": | ||||
| 		if len(buildDescriptorFilePath) == 0 { | ||||
| 			var err error | ||||
| 			buildDescriptorFilePath, err = searchDescriptor([]string{"version.txt", "VERSION"}, fileExists) | ||||
| 			if err != nil { | ||||
| 				return artifact, err | ||||
| 			} | ||||
| 		} | ||||
| 		artifact = &Versionfile{ | ||||
| 			path:             buildDescriptorFilePath, | ||||
| 			versioningScheme: "pep440", | ||||
| 		} | ||||
| 	case "sbt": | ||||
| 		if len(buildDescriptorFilePath) == 0 { | ||||
| 			buildDescriptorFilePath = "sbtDescriptor.json" | ||||
| 		} | ||||
| 		artifact = &JSONfile{ | ||||
| 			path:         buildDescriptorFilePath, | ||||
| 			versionField: "version", | ||||
| 		} | ||||
| 	default: | ||||
| 		return artifact, fmt.Errorf("build tool '%v' not supported", buildTool) | ||||
| @@ -52,3 +130,45 @@ func GetArtifact(buildTool, buildDescriptorFilePath string, opts *Options, execR | ||||
|  | ||||
| 	return artifact, nil | ||||
| } | ||||
|  | ||||
| func searchDescriptor(supported []string, existsFunc func(string) (bool, error)) (string, error) { | ||||
| 	var descriptor string | ||||
| 	for _, f := range supported { | ||||
| 		exists, _ := existsFunc(f) | ||||
| 		if exists { | ||||
| 			descriptor = f | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 	if len(descriptor) == 0 { | ||||
| 		return "", fmt.Errorf("no build descriptor available, supported: %v", supported) | ||||
| 	} | ||||
| 	return descriptor, nil | ||||
| } | ||||
|  | ||||
| func customArtifact(buildDescriptorFilePath, field, section string) (Artifact, error) { | ||||
| 	switch filepath.Ext(buildDescriptorFilePath) { | ||||
| 	case ".cfg", ".ini": | ||||
| 		return &INIfile{ | ||||
| 			path:           buildDescriptorFilePath, | ||||
| 			versionField:   field, | ||||
| 			versionSection: section, | ||||
| 		}, nil | ||||
| 	case ".json": | ||||
| 		return &JSONfile{ | ||||
| 			path:         buildDescriptorFilePath, | ||||
| 			versionField: field, | ||||
| 		}, nil | ||||
| 	case ".yaml", ".yml": | ||||
| 		return &YAMLfile{ | ||||
| 			path:         buildDescriptorFilePath, | ||||
| 			versionField: field, | ||||
| 		}, nil | ||||
| 	case ".txt", "": | ||||
| 		return &Versionfile{ | ||||
| 			path: buildDescriptorFilePath, | ||||
| 		}, nil | ||||
| 	default: | ||||
| 		return nil, fmt.Errorf("file type not supported: '%v'", buildDescriptorFilePath) | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -7,20 +7,168 @@ import ( | ||||
| ) | ||||
|  | ||||
| func TestGetArtifact(t *testing.T) { | ||||
| 	t.Run("maven", func(t *testing.T) { | ||||
| 		maven, err := GetArtifact("maven", "my/pom.xml", &Options{}, nil) | ||||
| 	t.Run("custom", func(t *testing.T) { | ||||
| 		custom, err := GetArtifact("custom", "test.ini", &Options{VersionField: "theversion", VersionSection: "test"}, nil) | ||||
|  | ||||
| 		assert.NoError(t, err) | ||||
|  | ||||
| 		theType, ok := custom.(*INIfile) | ||||
| 		assert.True(t, ok) | ||||
| 		assert.Equal(t, "test.ini", theType.path) | ||||
| 		assert.Equal(t, "theversion", theType.versionField) | ||||
| 		assert.Equal(t, "test", theType.versionSection) | ||||
| 		assert.Equal(t, "semver2", custom.VersioningScheme()) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("docker", func(t *testing.T) { | ||||
| 		docker, err := GetArtifact("docker", "test.ini", &Options{VersionSource: "custom", VersionField: "theversion", VersionSection: "test"}, nil) | ||||
|  | ||||
| 		assert.NoError(t, err) | ||||
|  | ||||
| 		theType, ok := docker.(*Docker) | ||||
| 		assert.True(t, ok) | ||||
| 		assert.Equal(t, "test.ini", theType.path) | ||||
| 		assert.Equal(t, "theversion", theType.options.VersionField) | ||||
| 		assert.Equal(t, "test", theType.options.VersionSection) | ||||
| 		assert.Equal(t, "maven", docker.VersioningScheme()) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("dub", func(t *testing.T) { | ||||
| 		dub, err := GetArtifact("dub", "", &Options{VersionField: "theversion"}, nil) | ||||
|  | ||||
| 		assert.NoError(t, err) | ||||
|  | ||||
| 		theType, ok := dub.(*JSONfile) | ||||
| 		assert.True(t, ok) | ||||
| 		assert.Equal(t, "dub.json", theType.path) | ||||
| 		assert.Equal(t, "version", theType.versionField) | ||||
| 		assert.Equal(t, "semver2", dub.VersioningScheme()) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("golang", func(t *testing.T) { | ||||
| 		fileExists = func(string) (bool, error) { return true, nil } | ||||
| 		golang, err := GetArtifact("golang", "", &Options{}, nil) | ||||
|  | ||||
| 		assert.NoError(t, err) | ||||
|  | ||||
| 		theType, ok := golang.(*Versionfile) | ||||
| 		assert.True(t, ok) | ||||
| 		assert.Equal(t, "VERSION", theType.path) | ||||
| 		assert.Equal(t, "semver2", golang.VersioningScheme()) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("golang - error", func(t *testing.T) { | ||||
| 		fileExists = func(string) (bool, error) { return false, nil } | ||||
| 		_, err := GetArtifact("golang", "", &Options{}, nil) | ||||
|  | ||||
| 		assert.EqualError(t, err, "no build descriptor available, supported: [VERSION version.txt]") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("maven", func(t *testing.T) { | ||||
| 		opts := Options{ | ||||
| 			ProjectSettingsFile: "projectsettings.xml", | ||||
| 			GlobalSettingsFile:  "globalsettings.xml", | ||||
| 			M2Path:              "m2/path", | ||||
| 		} | ||||
| 		maven, err := GetArtifact("maven", "", &opts, nil) | ||||
| 		assert.NoError(t, err) | ||||
|  | ||||
| 		theType, ok := maven.(*Maven) | ||||
| 		assert.True(t, ok) | ||||
| 		assert.Equal(t, "pom.xml", theType.pomPath) | ||||
| 		assert.Equal(t, opts.ProjectSettingsFile, theType.projectSettingsFile) | ||||
| 		assert.Equal(t, opts.GlobalSettingsFile, theType.globalSettingsFile) | ||||
| 		assert.Equal(t, opts.M2Path, theType.m2Path) | ||||
| 		assert.Equal(t, "maven", maven.VersioningScheme()) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("npm", func(t *testing.T) { | ||||
| 		npm, err := GetArtifact("npm", "my/package.json", &Options{}, nil) | ||||
| 	t.Run("mta", func(t *testing.T) { | ||||
| 		mta, err := GetArtifact("mta", "", &Options{VersionField: "theversion"}, nil) | ||||
|  | ||||
| 		assert.NoError(t, err) | ||||
|  | ||||
| 		theType, ok := mta.(*YAMLfile) | ||||
| 		assert.True(t, ok) | ||||
| 		assert.Equal(t, "mta.yaml", theType.path) | ||||
| 		assert.Equal(t, "version", theType.versionField) | ||||
| 		assert.Equal(t, "semver2", mta.VersioningScheme()) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("npm", func(t *testing.T) { | ||||
| 		npm, err := GetArtifact("npm", "", &Options{VersionField: "theversion"}, nil) | ||||
|  | ||||
| 		assert.NoError(t, err) | ||||
|  | ||||
| 		theType, ok := npm.(*JSONfile) | ||||
| 		assert.True(t, ok) | ||||
| 		assert.Equal(t, "package.json", theType.path) | ||||
| 		assert.Equal(t, "version", theType.versionField) | ||||
| 		assert.Equal(t, "semver2", npm.VersioningScheme()) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("pip", func(t *testing.T) { | ||||
| 		fileExists = func(string) (bool, error) { return true, nil } | ||||
| 		pip, err := GetArtifact("pip", "", &Options{}, nil) | ||||
|  | ||||
| 		assert.NoError(t, err) | ||||
|  | ||||
| 		theType, ok := pip.(*Versionfile) | ||||
| 		assert.True(t, ok) | ||||
| 		assert.Equal(t, "version.txt", theType.path) | ||||
| 		assert.Equal(t, "pep440", pip.VersioningScheme()) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("pip - error", func(t *testing.T) { | ||||
| 		fileExists = func(string) (bool, error) { return false, nil } | ||||
| 		_, err := GetArtifact("pip", "", &Options{}, nil) | ||||
|  | ||||
| 		assert.EqualError(t, err, "no build descriptor available, supported: [version.txt VERSION]") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("sbt", func(t *testing.T) { | ||||
| 		sbt, err := GetArtifact("sbt", "", &Options{VersionField: "theversion"}, nil) | ||||
|  | ||||
| 		assert.NoError(t, err) | ||||
|  | ||||
| 		theType, ok := sbt.(*JSONfile) | ||||
| 		assert.True(t, ok) | ||||
| 		assert.Equal(t, "sbtDescriptor.json", theType.path) | ||||
| 		assert.Equal(t, "version", theType.versionField) | ||||
| 		assert.Equal(t, "semver2", sbt.VersioningScheme()) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("not supported build tool", func(t *testing.T) { | ||||
| 		_, err := GetArtifact("nosupport", "whatever", &Options{}, nil) | ||||
| 		assert.EqualError(t, err, "build tool 'nosupport' not supported") | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestCustomArtifact(t *testing.T) { | ||||
| 	tt := []struct { | ||||
| 		file        string | ||||
| 		field       string | ||||
| 		section     string | ||||
| 		expected    Artifact | ||||
| 		expectedErr string | ||||
| 	}{ | ||||
| 		{file: "not.supported", expectedErr: "file type not supported: 'not.supported'"}, | ||||
| 		{file: "test.cfg", field: "testField", section: "testSection", expected: &INIfile{path: "test.cfg", versionField: "testField", versionSection: "testSection"}}, | ||||
| 		{file: "test.ini", field: "testField", section: "testSection", expected: &INIfile{path: "test.ini", versionField: "testField", versionSection: "testSection"}}, | ||||
| 		{file: "test.json", field: "testField", expected: &JSONfile{path: "test.json", versionField: "testField"}}, | ||||
| 		{file: "test.yaml", field: "testField", expected: &YAMLfile{path: "test.yaml", versionField: "testField"}}, | ||||
| 		{file: "test.yml", field: "testField", expected: &YAMLfile{path: "test.yml", versionField: "testField"}}, | ||||
| 		{file: "test.txt", expected: &Versionfile{path: "test.txt"}}, | ||||
| 		{file: "test", expected: &Versionfile{path: "test"}}, | ||||
| 	} | ||||
|  | ||||
| 	for _, test := range tt { | ||||
| 		res, err := customArtifact(test.file, test.field, test.section) | ||||
|  | ||||
| 		if len(test.expectedErr) == 0 { | ||||
| 			assert.NoError(t, err) | ||||
| 			assert.Equal(t, test.expected, res) | ||||
| 		} else { | ||||
| 			assert.EqualError(t, err, test.expectedErr) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
							
								
								
									
										79
									
								
								pkg/versioning/yamlfile.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								pkg/versioning/yamlfile.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,79 @@ | ||||
| package versioning | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/ghodss/yaml" | ||||
| 	"github.com/pkg/errors" | ||||
| ) | ||||
|  | ||||
| // YAMLfile defines an artifact using a yaml file for versioning | ||||
| type YAMLfile struct { | ||||
| 	path         string | ||||
| 	content      map[string]interface{} | ||||
| 	versionField string | ||||
| 	readFile     func(string) ([]byte, error) | ||||
| 	writeFile    func(string, []byte, os.FileMode) error | ||||
| } | ||||
|  | ||||
| func (y *YAMLfile) init() { | ||||
| 	if len(y.versionField) == 0 { | ||||
| 		y.versionField = "version" | ||||
| 	} | ||||
| 	if y.readFile == nil { | ||||
| 		y.readFile = ioutil.ReadFile | ||||
| 	} | ||||
|  | ||||
| 	if y.writeFile == nil { | ||||
| 		y.writeFile = ioutil.WriteFile | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // VersioningScheme returns the relevant versioning scheme | ||||
| func (y *YAMLfile) VersioningScheme() string { | ||||
| 	return "semver2" | ||||
| } | ||||
|  | ||||
| // GetVersion returns the current version of the artifact with a YAML-based build descriptor | ||||
| func (y *YAMLfile) GetVersion() (string, error) { | ||||
| 	y.init() | ||||
|  | ||||
| 	content, err := y.readFile(y.path) | ||||
| 	if err != nil { | ||||
| 		return "", errors.Wrapf(err, "failed to read file '%v'", y.path) | ||||
| 	} | ||||
|  | ||||
| 	err = yaml.Unmarshal(content, &y.content) | ||||
| 	if err != nil { | ||||
| 		return "", errors.Wrapf(err, "failed to read yaml content of file '%v'", y.content) | ||||
| 	} | ||||
|  | ||||
| 	return strings.TrimSpace(fmt.Sprint(y.content[y.versionField])), nil | ||||
| } | ||||
|  | ||||
| // SetVersion updates the version of the artifact with a YAML-based build descriptor | ||||
| func (y *YAMLfile) SetVersion(version string) error { | ||||
| 	y.init() | ||||
|  | ||||
| 	if y.content == nil { | ||||
| 		_, err := y.GetVersion() | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	y.content[y.versionField] = version | ||||
|  | ||||
| 	content, err := yaml.Marshal(y.content) | ||||
| 	if err != nil { | ||||
| 		return errors.Wrapf(err, "failed to create yaml content for '%v'", y.path) | ||||
| 	} | ||||
| 	err = y.writeFile(y.path, content, 0700) | ||||
| 	if err != nil { | ||||
| 		return errors.Wrapf(err, "failed to write file '%v'", y.path) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										57
									
								
								pkg/versioning/yamlfile_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								pkg/versioning/yamlfile_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | ||||
| package versioning | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
|  | ||||
| func TestYAMLfileGetVersion(t *testing.T) { | ||||
| 	t.Run("success case", func(t *testing.T) { | ||||
| 		yamlfile := YAMLfile{ | ||||
| 			path:     "my.yaml", | ||||
| 			readFile: func(filename string) ([]byte, error) { return []byte(`version: 1.2.3`), nil }, | ||||
| 		} | ||||
| 		version, err := yamlfile.GetVersion() | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Equal(t, "1.2.3", version) | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("error case", func(t *testing.T) { | ||||
| 		yamlfile := YAMLfile{ | ||||
| 			path:         "my.yaml", | ||||
| 			versionField: "theversion", | ||||
| 			readFile:     func(filename string) ([]byte, error) { return []byte{}, fmt.Errorf("read error") }, | ||||
| 		} | ||||
| 		_, err := yamlfile.GetVersion() | ||||
| 		assert.EqualError(t, err, "failed to read file 'my.yaml': read error") | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestYAMLfileSetVersion(t *testing.T) { | ||||
| 	t.Run("success case", func(t *testing.T) { | ||||
| 		var content []byte | ||||
| 		yamlfile := YAMLfile{ | ||||
| 			path:         "my.yaml", | ||||
| 			versionField: "theversion", | ||||
| 			readFile:     func(filename string) ([]byte, error) { return []byte(`theversion: 1.2.3`), nil }, | ||||
| 			writeFile:    func(filename string, filecontent []byte, mode os.FileMode) error { content = filecontent; return nil }, | ||||
| 		} | ||||
| 		err := yamlfile.SetVersion("1.2.4") | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.Contains(t, string(content), "theversion: 1.2.4") | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("error case", func(t *testing.T) { | ||||
| 		yamlfile := YAMLfile{ | ||||
| 			path:         "my.yaml", | ||||
| 			versionField: "theversion", | ||||
| 			readFile:     func(filename string) ([]byte, error) { return []byte(`theversion: 1.2.3`), nil }, | ||||
| 			writeFile:    func(filename string, filecontent []byte, mode os.FileMode) error { return fmt.Errorf("write error") }, | ||||
| 		} | ||||
| 		err := yamlfile.SetVersion("1.2.4") | ||||
| 		assert.EqualError(t, err, "failed to write file 'my.yaml': write error") | ||||
| 	}) | ||||
| } | ||||
| @@ -43,12 +43,38 @@ metadata: | ||||
|     Unlike for the _Continuous Deloyment_ pattern descibed above, in this case there is no dedicated tagging required for the build process since the version is already available in the repository. | ||||
|  | ||||
|     Configuration of this pattern is done via `versioningType: library`. | ||||
|  | ||||
|     ### Support of additional build tools | ||||
|  | ||||
|     Besides the `buildTools` provided out of the box (like `maven`, `mta`, `npm`, ...) it is possible to set `buildTool: custom`. | ||||
|  | ||||
|     This allows you to provide automatic versioning for tools using a: | ||||
|  | ||||
|     #### file with the version as only content: | ||||
|  | ||||
|     Define `buildTool: custom` as well as `filePath: <path to your file>` | ||||
|  | ||||
|     **Please note:** `<path to your file>` need to point either to a `*.txt` file or to a file without extension. | ||||
|  | ||||
|     #### `ini` file containing the version: | ||||
|  | ||||
|     Define `buildTool: custom`, `filePath: <path to your ini-file>` as well as parameters `versionSection` and `versionSource` to point to the version location (section & parameter name) within the file. | ||||
|  | ||||
|     **Please note:** `<path to your file>` need to point either to a `*.cfg` or a `*.ini` file. | ||||
|  | ||||
|     #### `json` file containing the version: | ||||
|  | ||||
|     Define `buildTool: custom`, `filePath: <path to your *.json file` as well as parameter `versionSource` to point to the parameter containing the version. | ||||
|  | ||||
|     #### `yaml` file containing the version | ||||
|  | ||||
|     Define `buildTool: custom`, `filePath: <path to your *.yml/*.yaml file` as well as parameter `versionSource` to point to the parameter containing the version. | ||||
| spec: | ||||
|   inputs: | ||||
|     params: | ||||
|       - name: buildTool | ||||
|         type: string | ||||
|         description: Defines the tool which is used for building the artifact. | ||||
|         description: Defines the tool which is used for building the artifact. Supports `custom`, `dub`, `golang`, `maven`, `mta`, `npm`, `pip`, `sbt`. | ||||
|         mandatory: true | ||||
|         scope: | ||||
|         - GENERAL | ||||
| @@ -65,9 +91,23 @@ spec: | ||||
|         - STAGES | ||||
|         - STEPS | ||||
|         default: Project Piper | ||||
|       - name: customversionField | ||||
|         type: string | ||||
|         description: "For `buildTool: custom`: Defines the field which contains the version in the descriptor file." | ||||
|         scope: | ||||
|         - PARAMETERS | ||||
|         - STAGES | ||||
|         - STEPS | ||||
|       - name: customVersionSection | ||||
|         type: string | ||||
|         description: "For `buildTool: custom`: Defines the section for version retrieval in vase a *.ini/*.cfg file is used." | ||||
|         scope: | ||||
|         - PARAMETERS | ||||
|         - STAGES | ||||
|         - STEPS | ||||
|       - name: dockerVersionSource | ||||
|         type: string | ||||
|         description: "For Docker only: Specifies the source to be used for for generating the automatic version. * This can either be the version of the base image - as retrieved from the `FROM` statement within the Dockerfile, e.g. `FROM jenkins:2.46.2` * Alternatively the name of an environment variable defined in the Docker image can be used which contains the version number, e.g. `ENV MY_VERSION 1.2.3`." | ||||
|         description: "For `buildTool: docker`: Defines the source of the version. Can be `FROM`, any supported _buildTool_ or an environment variable name." | ||||
|         scope: | ||||
|         - PARAMETERS | ||||
|         - STAGES | ||||
|   | ||||
		Reference in New Issue
	
	Block a user