mirror of
https://github.com/SAP/jenkins-library.git
synced 2025-01-16 05:16:08 +02:00
piper: Use stageName from parametersJSON, log value and source (#1920)
stageName from parametersJSON was ignored up until now and there was a TODO in the code. The precedence from the TODO is not clear to me. It said "first env.STAGE_NAME, second: parametersJSON, third: flag". So maybe I implemented it wrongly, but it would be easy to change. Right now, STAGE_NAME is always in the ENV when piper is called from Jenkins, but to mimic the behavior of being able to pass `stageName` in the parameters and override the ENV value, this is what happens in go as well now. The reason why `stageName` needs to be evaluated before other step parameters is that it affects config evaluation. So I've added a function which is called first in `PrepareConfig()`.
This commit is contained in:
parent
6a71feeafd
commit
b1a0cb089c
@ -33,6 +33,7 @@ func ConfigCommand() *cobra.Command {
|
||||
path, _ := os.Getwd()
|
||||
fatalHook := &log.FatalHook{CorrelationID: GeneralConfig.CorrelationID, Path: path}
|
||||
log.RegisterHook(fatalHook)
|
||||
initStageName(false)
|
||||
},
|
||||
Run: func(cmd *cobra.Command, _ []string) {
|
||||
err := generateConfig()
|
||||
|
56
cmd/piper.go
56
cmd/piper.go
@ -52,7 +52,6 @@ var rootCmd = &cobra.Command{
|
||||
This project 'Piper' binary provides a CI/CD step library.
|
||||
It contains many steps which can be used within CI/CD systems as well as directly on e.g. a developer's machine.
|
||||
`,
|
||||
//ToDo: respect stageName to also come from parametersJSON -> first env.STAGE_NAME, second: parametersJSON, third: flag
|
||||
}
|
||||
|
||||
// GeneralConfig contains global configuration flags for piper binary
|
||||
@ -113,7 +112,7 @@ func addRootFlags(rootCmd *cobra.Command) {
|
||||
rootCmd.PersistentFlags().BoolVar(&GeneralConfig.IgnoreCustomDefaults, "ignoreCustomDefaults", false, "Disables evaluation of the parameter 'customDefaults' in the pipeline configuration file")
|
||||
rootCmd.PersistentFlags().StringVar(&GeneralConfig.ParametersJSON, "parametersJSON", os.Getenv("PIPER_parametersJSON"), "Parameters to be considered in JSON format")
|
||||
rootCmd.PersistentFlags().StringVar(&GeneralConfig.EnvRootPath, "envRootPath", ".pipeline", "Root path to Piper pipeline shared environments")
|
||||
rootCmd.PersistentFlags().StringVar(&GeneralConfig.StageName, "stageName", os.Getenv("STAGE_NAME"), "Name of the stage for which configuration should be included")
|
||||
rootCmd.PersistentFlags().StringVar(&GeneralConfig.StageName, "stageName", "", "Name of the stage for which configuration should be included")
|
||||
rootCmd.PersistentFlags().StringVar(&GeneralConfig.StepConfigJSON, "stepConfigJSON", os.Getenv("PIPER_stepConfigJSON"), "Step configuration in JSON format")
|
||||
rootCmd.PersistentFlags().BoolVar(&GeneralConfig.NoTelemetry, "noTelemetry", false, "Disables telemetry reporting")
|
||||
rootCmd.PersistentFlags().BoolVarP(&GeneralConfig.Verbose, "verbose", "v", false, "verbose output")
|
||||
@ -121,9 +120,60 @@ func addRootFlags(rootCmd *cobra.Command) {
|
||||
|
||||
}
|
||||
|
||||
const stageNameEnvKey = "STAGE_NAME"
|
||||
|
||||
// initStageName initializes GeneralConfig.StageName from either GeneralConfig.ParametersJSON
|
||||
// or the environment variable 'STAGE_NAME', unless it has been provided as command line option.
|
||||
// Log output needs to be suppressed via outputToLog by the getConfig step.
|
||||
func initStageName(outputToLog bool) {
|
||||
var stageNameSource string
|
||||
if outputToLog {
|
||||
defer func() {
|
||||
log.Entry().Infof("Using stageName '%s' from %s", GeneralConfig.StageName, stageNameSource)
|
||||
}()
|
||||
}
|
||||
|
||||
if GeneralConfig.StageName != "" {
|
||||
// Means it was given as command line argument and has the highest precedence
|
||||
stageNameSource = "command line arguments"
|
||||
return
|
||||
}
|
||||
|
||||
// Use stageName from ENV as fall-back, for when extracting it from parametersJSON fails below
|
||||
GeneralConfig.StageName = os.Getenv(stageNameEnvKey)
|
||||
stageNameSource = fmt.Sprintf("env variable '%s'", stageNameEnvKey)
|
||||
|
||||
if len(GeneralConfig.ParametersJSON) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
var params map[string]interface{}
|
||||
err := json.Unmarshal([]byte(GeneralConfig.ParametersJSON), ¶ms)
|
||||
if err != nil {
|
||||
if outputToLog {
|
||||
log.Entry().Infof("Failed to extract 'stageName' from parametersJSON: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
stageName, hasKey := params["stageName"]
|
||||
if !hasKey {
|
||||
return
|
||||
}
|
||||
|
||||
if stageNameString, ok := stageName.(string); ok && stageNameString != "" {
|
||||
stageNameSource = "parametersJSON"
|
||||
GeneralConfig.StageName = stageNameString
|
||||
}
|
||||
}
|
||||
|
||||
// PrepareConfig reads step configuration from various sources and merges it (defaults, config file, flags, ...)
|
||||
func PrepareConfig(cmd *cobra.Command, metadata *config.StepData, stepName string, options interface{}, openFile func(s string) (io.ReadCloser, error)) error {
|
||||
|
||||
log.SetFormatter(GeneralConfig.LogFormat)
|
||||
|
||||
initStageName(true)
|
||||
|
||||
filters := metadata.GetParameterFilters()
|
||||
|
||||
// add telemetry parameter "collectTelemetryData" to ALL, GENERAL and PARAMETER filters
|
||||
@ -138,8 +188,6 @@ func PrepareConfig(cmd *cobra.Command, metadata *config.StepData, stepName strin
|
||||
var myConfig config.Config
|
||||
var stepConfig config.StepConfig
|
||||
|
||||
log.SetFormatter(GeneralConfig.LogFormat)
|
||||
|
||||
if len(GeneralConfig.StepConfigJSON) != 0 {
|
||||
// ignore config & defaults in favor of passed stepConfigJSON
|
||||
stepConfig = config.GetStepConfigWithJSON(flagValues, GeneralConfig.StepConfigJSON, filters)
|
||||
|
@ -31,6 +31,56 @@ func TestAddRootFlags(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
func TestAdoptStageNameFromParametersJSON(t *testing.T) {
|
||||
tt := []struct {
|
||||
name string
|
||||
stageNameArg string
|
||||
stageNameEnv string
|
||||
stageNameJSON string
|
||||
}{
|
||||
{name: "no stage name", stageNameArg: "", stageNameEnv: "", stageNameJSON: ""},
|
||||
{name: "stage name arg+env", stageNameArg: "arg", stageNameEnv: "env", stageNameJSON: "json"},
|
||||
{name: "stage name env", stageNameArg: "", stageNameEnv: "env", stageNameJSON: "json"},
|
||||
{name: "stage name json", stageNameArg: "", stageNameEnv: "", stageNameJSON: "json"},
|
||||
{name: "stage name arg", stageNameArg: "arg", stageNameEnv: "", stageNameJSON: "json"},
|
||||
}
|
||||
|
||||
for _, test := range tt {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
// init
|
||||
GeneralConfig.StageName = test.stageNameArg
|
||||
|
||||
resetValue := os.Getenv(stageNameEnvKey)
|
||||
defer func() { _ = os.Setenv(stageNameEnvKey, resetValue) }()
|
||||
|
||||
err := os.Setenv(stageNameEnvKey, test.stageNameEnv)
|
||||
if err != nil {
|
||||
t.Fatalf("could not set env var %s", stageNameEnvKey)
|
||||
}
|
||||
|
||||
if test.stageNameJSON != "" {
|
||||
GeneralConfig.ParametersJSON = fmt.Sprintf("{\"stageName\":\"%s\"}", test.stageNameJSON)
|
||||
} else {
|
||||
GeneralConfig.ParametersJSON = "{}"
|
||||
}
|
||||
// test
|
||||
initStageName(false)
|
||||
|
||||
// assert
|
||||
// Order of if-clauses reflects wanted precedence.
|
||||
if test.stageNameArg != "" {
|
||||
assert.Equal(t, test.stageNameArg, GeneralConfig.StageName)
|
||||
} else if test.stageNameJSON != "" {
|
||||
assert.Equal(t, test.stageNameJSON, GeneralConfig.StageName)
|
||||
} else if test.stageNameEnv != "" {
|
||||
assert.Equal(t, test.stageNameEnv, GeneralConfig.StageName)
|
||||
} else {
|
||||
assert.Equal(t, "", GeneralConfig.StageName)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrepareConfig(t *testing.T) {
|
||||
defaultsBak := GeneralConfig.DefaultConfig
|
||||
GeneralConfig.DefaultConfig = []string{"testDefaults.yml"}
|
||||
@ -73,7 +123,7 @@ func TestPrepareConfig(t *testing.T) {
|
||||
}
|
||||
|
||||
err := PrepareConfig(testCmd, &metadata, "testStep", &testOptions, mock.OpenFileMock)
|
||||
assert.NoError(t, err, "no error expected but error occured")
|
||||
assert.NoError(t, err, "no error expected but error occurred")
|
||||
|
||||
//assert config
|
||||
assert.Equal(t, "testValue", testOptions.TestParam, "wrong value retrieved from config")
|
||||
@ -93,7 +143,7 @@ func TestPrepareConfig(t *testing.T) {
|
||||
metadata := config.StepData{}
|
||||
|
||||
err := PrepareConfig(testCmd, &metadata, "testStep", &testOptions, mock.OpenFileMock)
|
||||
assert.Error(t, err, "error expected but none occured")
|
||||
assert.Error(t, err, "error expected but none occurred")
|
||||
})
|
||||
})
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user