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 
			
		
		
		
	This reverts commit 7f4fab762d.
			
			
This commit is contained in:
		
							
								
								
									
										95
									
								
								cmd/piper.go
									
									
									
									
									
								
							
							
						
						
									
										95
									
								
								cmd/piper.go
									
									
									
									
									
								
							| @@ -7,7 +7,6 @@ import ( | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"reflect" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/SAP/jenkins-library/pkg/config" | ||||
| @@ -89,8 +88,8 @@ func Execute() { | ||||
| 	rootCmd.AddCommand(GctsCreateRepositoryCommand()) | ||||
| 	rootCmd.AddCommand(GctsExecuteABAPUnitTestsCommand()) | ||||
| 	rootCmd.AddCommand(GctsDeployCommand()) | ||||
| 	rootCmd.AddCommand(GctsRollbackCommand()) | ||||
| 	rootCmd.AddCommand(MalwareExecuteScanCommand()) | ||||
| 	rootCmd.AddCommand(GctsRollbackCommand()) | ||||
| 	rootCmd.AddCommand(WhitesourceExecuteScanCommand()) | ||||
| 	rootCmd.AddCommand(GctsCloneRepositoryCommand()) | ||||
| 	rootCmd.AddCommand(JsonApplyPatchCommand()) | ||||
| @@ -210,8 +209,6 @@ func PrepareConfig(cmd *cobra.Command, metadata *config.StepData, stepName strin | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| var errIncompatibleTypes = fmt.Errorf("incompatible types") | ||||
|  | ||||
| func checkTypes(config map[string]interface{}, options interface{}) map[string]interface{} { | ||||
| 	optionsType := getStepOptionsStructType(options) | ||||
|  | ||||
| @@ -222,84 +219,42 @@ func checkTypes(config map[string]interface{}, options interface{}) map[string]i | ||||
| 		} | ||||
|  | ||||
| 		paramValueType := reflect.ValueOf(config[paramName]) | ||||
| 		if optionsField.Type.Kind() == paramValueType.Kind() { | ||||
| 			// Types already match, nothing to do | ||||
| 		if paramValueType.Kind() != reflect.String { | ||||
| 			// Type check is limited to strings at the moment | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		var typeError error = nil | ||||
| 		paramValue := paramValueType.String() | ||||
| 		logWarning := true | ||||
|  | ||||
| 		switch paramValueType.Kind() { | ||||
| 		switch optionsField.Type.Kind() { | ||||
| 		case reflect.String: | ||||
| 			typeError = convertValueFromString(config, optionsField, paramName, paramValueType.String()) | ||||
| 		case reflect.Float32, reflect.Float64: | ||||
| 			typeError = convertValueFromFloat(config, optionsField, paramName, paramValueType.Float()) | ||||
| 		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: | ||||
| 			typeError = convertValueFromInt(config, optionsField, paramName, paramValueType.Int()) | ||||
| 		default: | ||||
| 			typeError = errIncompatibleTypes | ||||
| 			// Types match, ignore | ||||
| 			logWarning = false | ||||
| 		case reflect.Slice, reflect.Array: | ||||
| 			// Could do automatic conversion for those types in theory, | ||||
| 			// but that might obscure what really happens in error cases. | ||||
| 			log.Entry().Fatalf("Type mismatch in configuration for option '%s'. Expected type to be a list (or slice, or array) but got %s.", paramName, paramValueType.Kind()) | ||||
| 		case reflect.Bool: | ||||
| 			// Sensible to convert strings "true"/"false" to respective boolean values as it is | ||||
| 			// common practice to write booleans as string in yaml files. | ||||
| 			paramValue = strings.ToLower(paramValue) | ||||
| 			if paramValue == "true" { | ||||
| 				config[paramName] = true | ||||
| 				logWarning = false | ||||
| 			} else if paramValue == "false" { | ||||
| 				config[paramName] = false | ||||
| 				logWarning = false | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if typeError != nil { | ||||
| 			log.Entry().WithError(typeError).Fatalf( | ||||
| 				"config value for '%s' is of unexpected type %s, expected %s", | ||||
| 				paramName, paramValueType.Kind(), optionsField.Type.Kind()) | ||||
| 		if logWarning { | ||||
| 			log.Entry().Warnf("Config value for '%s' is of unexpected type and is ignored", paramName) | ||||
| 		} | ||||
| 	} | ||||
| 	return config | ||||
| } | ||||
|  | ||||
| func convertValueFromString(config map[string]interface{}, optionsField *reflect.StructField, paramName, paramValue string) error { | ||||
| 	switch optionsField.Type.Kind() { | ||||
| 	case reflect.Slice, reflect.Array: | ||||
| 		// Could do automatic conversion for those types in theory, | ||||
| 		// but that might obscure what really happens in error cases. | ||||
| 		return fmt.Errorf("expected type to be a list (or slice, or array) but got string") | ||||
| 	case reflect.Bool: | ||||
| 		// Sensible to convert strings "true"/"false" to respective boolean values as it is | ||||
| 		// common practice to write booleans as string in yaml files. | ||||
| 		paramValue = strings.ToLower(paramValue) | ||||
| 		if paramValue == "true" { | ||||
| 			config[paramName] = true | ||||
| 			return nil | ||||
| 		} else if paramValue == "false" { | ||||
| 			config[paramName] = false | ||||
| 			return nil | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return errIncompatibleTypes | ||||
| } | ||||
|  | ||||
| func convertValueFromFloat(config map[string]interface{}, optionsField *reflect.StructField, paramName string, paramValue float64) error { | ||||
| 	switch optionsField.Type.Kind() { | ||||
| 	case reflect.String: | ||||
| 		config[paramName] = strconv.FormatFloat(paramValue, 'f', -1, 64) | ||||
| 		return nil | ||||
| 	case reflect.Float32: | ||||
| 		config[paramName] = float32(paramValue) | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	return errIncompatibleTypes | ||||
| } | ||||
|  | ||||
| func convertValueFromInt(config map[string]interface{}, optionsField *reflect.StructField, paramName string, paramValue int64) error { | ||||
| 	switch optionsField.Type.Kind() { | ||||
| 	case reflect.String: | ||||
| 		config[paramName] = strconv.FormatInt(paramValue, 10) | ||||
| 		return nil | ||||
| 	case reflect.Float32: | ||||
| 		config[paramName] = float32(paramValue) | ||||
| 		return nil | ||||
| 	case reflect.Float64: | ||||
| 		config[paramName] = float64(paramValue) | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	return errIncompatibleTypes | ||||
| } | ||||
|  | ||||
| func findStructFieldByJSONTag(tagName string, optionsType reflect.Type) *reflect.StructField { | ||||
| 	for i := 0; i < optionsType.NumField(); i++ { | ||||
| 		field := optionsType.Field(i) | ||||
|   | ||||
| @@ -134,14 +134,6 @@ func TestGetProjectConfigFile(t *testing.T) { | ||||
| func TestConvertTypes(t *testing.T) { | ||||
| 	t.Run("Converts strings to booleans", func(t *testing.T) { | ||||
| 		// Init | ||||
| 		hasFailed := false | ||||
|  | ||||
| 		exitFunc := log.Entry().Logger.ExitFunc | ||||
| 		log.Entry().Logger.ExitFunc = func(int) { | ||||
| 			hasFailed = true | ||||
| 		} | ||||
| 		defer func() { log.Entry().Logger.ExitFunc = exitFunc }() | ||||
|  | ||||
| 		options := struct { | ||||
| 			Foo bool `json:"foo,omitempty"` | ||||
| 			Bar bool `json:"bar,omitempty"` | ||||
| @@ -164,71 +156,6 @@ func TestConvertTypes(t *testing.T) { | ||||
| 		assert.Equal(t, true, stepConfig["bar"]) | ||||
| 		assert.Equal(t, false, options.Foo) | ||||
| 		assert.Equal(t, true, options.Bar) | ||||
| 		assert.False(t, hasFailed, "Expected checkTypes() NOT to exit via logging framework") | ||||
| 	}) | ||||
| 	t.Run("Converts numbers to strings", func(t *testing.T) { | ||||
| 		// Init | ||||
| 		hasFailed := false | ||||
|  | ||||
| 		exitFunc := log.Entry().Logger.ExitFunc | ||||
| 		log.Entry().Logger.ExitFunc = func(int) { | ||||
| 			hasFailed = true | ||||
| 		} | ||||
| 		defer func() { log.Entry().Logger.ExitFunc = exitFunc }() | ||||
|  | ||||
| 		options := struct { | ||||
| 			Foo string `json:"foo,omitempty"` | ||||
| 			Bar string `json:"bar,omitempty"` | ||||
| 		}{} | ||||
|  | ||||
| 		stepConfig := map[string]interface{}{} | ||||
| 		stepConfig["foo"] = 1.5 | ||||
| 		stepConfig["bar"] = 42 | ||||
|  | ||||
| 		// Test | ||||
| 		stepConfig = checkTypes(stepConfig, options) | ||||
|  | ||||
| 		confJSON, _ := json.Marshal(stepConfig) | ||||
| 		_ = json.Unmarshal(confJSON, &options) | ||||
|  | ||||
| 		// Assert | ||||
| 		assert.Equal(t, "1.5", stepConfig["foo"]) | ||||
| 		assert.Equal(t, "42", stepConfig["bar"]) | ||||
| 		assert.Equal(t, "1.5", options.Foo) | ||||
| 		assert.Equal(t, "42", options.Bar) | ||||
| 		assert.False(t, hasFailed, "Expected checkTypes() NOT to exit via logging framework") | ||||
| 	}) | ||||
| 	t.Run("Keeps numbers", func(t *testing.T) { | ||||
| 		// Init | ||||
| 		hasFailed := false | ||||
|  | ||||
| 		exitFunc := log.Entry().Logger.ExitFunc | ||||
| 		log.Entry().Logger.ExitFunc = func(int) { | ||||
| 			hasFailed = true | ||||
| 		} | ||||
| 		defer func() { log.Entry().Logger.ExitFunc = exitFunc }() | ||||
|  | ||||
| 		options := struct { | ||||
| 			Foo int     `json:"foo,omitempty"` | ||||
| 			Bar float32 `json:"bar,omitempty"` | ||||
| 		}{} | ||||
|  | ||||
| 		stepConfig := map[string]interface{}{} | ||||
| 		stepConfig["foo"] = 1 | ||||
| 		stepConfig["bar"] = 42 | ||||
|  | ||||
| 		// Test | ||||
| 		stepConfig = checkTypes(stepConfig, options) | ||||
|  | ||||
| 		confJSON, _ := json.Marshal(stepConfig) | ||||
| 		_ = json.Unmarshal(confJSON, &options) | ||||
|  | ||||
| 		// Assert | ||||
| 		assert.Equal(t, 1, stepConfig["foo"]) | ||||
| 		assert.Equal(t, float32(42.0), stepConfig["bar"]) | ||||
| 		assert.Equal(t, 1, options.Foo) | ||||
| 		assert.Equal(t, float32(42.0), options.Bar) | ||||
| 		assert.False(t, hasFailed, "Expected checkTypes() NOT to exit via logging framework") | ||||
| 	}) | ||||
| 	t.Run("Exits on unsupported type mismatch", func(t *testing.T) { | ||||
| 		// Init | ||||
|   | ||||
		Reference in New Issue
	
	Block a user