github.com/ouraigua/jenkins-library@v0.0.0-20231028010029-fbeaf2f3aa9b/pkg/config/run.go (about) 1 package config 2 3 import ( 4 "fmt" 5 "io" 6 7 "github.com/SAP/jenkins-library/pkg/piperutils" 8 "github.com/ghodss/yaml" 9 "github.com/pkg/errors" 10 ) 11 12 // RunConfig ... 13 type RunConfig struct { 14 StageConfigFile io.ReadCloser 15 StageConfig StageConfig 16 RunStages map[string]bool 17 RunSteps map[string]map[string]bool 18 OpenFile func(s string, t map[string]string) (io.ReadCloser, error) 19 FileUtils *piperutils.Files 20 } 21 22 type RunConfigV1 struct { 23 RunConfig 24 PipelineConfig PipelineDefinitionV1 25 } 26 27 type StageConfig struct { 28 Stages map[string]StepConditions `json:"stages,omitempty"` 29 } 30 31 type StepConditions struct { 32 Conditions map[string]map[string]interface{} `json:"stepConditions,omitempty"` 33 } 34 35 type PipelineDefinitionV1 struct { 36 APIVersion string `json:"apiVersion"` 37 Kind string `json:"kind"` 38 Metadata Metadata `json:"metadata"` 39 Spec Spec `json:"spec"` 40 openFile func(s string, t map[string]string) (io.ReadCloser, error) 41 runSteps map[string]map[string]bool 42 } 43 44 type Metadata struct { 45 Name string `json:"name,omitempty"` 46 DisplayName string `json:"displayName,omitempty"` 47 Description string `json:"description,omitempty"` 48 } 49 50 type Spec struct { 51 Stages []Stage `json:"stages"` 52 } 53 54 type Stage struct { 55 Name string `json:"name,omitempty"` 56 DisplayName string `json:"displayName,omitempty"` 57 Description string `json:"description,omitempty"` 58 Steps []Step `json:"steps,omitempty"` 59 } 60 61 type Step struct { 62 Name string `json:"name,omitempty"` 63 Description string `json:"description,omitempty"` 64 Conditions []StepCondition `json:"conditions,omitempty"` 65 NotActiveConditions []StepCondition `json:"notActiveConditions,omitempty"` 66 Orchestrators []string `json:"orchestrators,omitempty"` 67 } 68 69 type StepCondition struct { 70 Config map[string][]interface{} `json:"config,omitempty"` 71 ConfigKey string `json:"configKey,omitempty"` 72 FilePattern string `json:"filePattern,omitempty"` 73 FilePatternFromConfig string `json:"filePatternFromConfig,omitempty"` 74 Inactive bool `json:"inactive,omitempty"` 75 OnlyActiveStepInStage bool `json:"onlyActiveStepInStage,omitempty"` 76 NpmScript string `json:"npmScript,omitempty"` 77 CommonPipelineEnvironment map[string]interface{} `json:"commonPipelineEnvironment,omitempty"` 78 PipelineEnvironmentFilled string `json:"pipelineEnvironmentFilled,omitempty"` 79 } 80 81 func (r *RunConfigV1) InitRunConfigV1(config *Config, utils piperutils.FileUtils, envRootPath string) error { 82 83 if len(r.PipelineConfig.Spec.Stages) == 0 { 84 if err := r.LoadConditionsV1(); err != nil { 85 return fmt.Errorf("failed to load pipeline run conditions: %w", err) 86 } 87 } 88 89 err := r.evaluateConditionsV1(config, utils, envRootPath) 90 if err != nil { 91 return fmt.Errorf("failed to evaluate step conditions: %w", err) 92 } 93 94 return nil 95 } 96 97 // InitRunConfig ... 98 func (r *RunConfig) InitRunConfig(config *Config, filters map[string]StepFilters, parameters map[string][]StepParameters, 99 secrets map[string][]StepSecrets, stepAliases map[string][]Alias, glob func(pattern string) (matches []string, err error), 100 openFile func(s string, t map[string]string) (io.ReadCloser, error)) error { 101 r.OpenFile = openFile 102 r.RunSteps = map[string]map[string]bool{} 103 104 if len(r.StageConfig.Stages) == 0 { 105 if err := r.loadConditions(); err != nil { 106 return errors.Wrap(err, "failed to load pipeline run conditions") 107 } 108 } 109 110 err := r.evaluateConditions(config, filters, parameters, secrets, stepAliases, glob) 111 if err != nil { 112 return errors.Wrap(err, "failed to evaluate step conditions: %v") 113 } 114 115 return nil 116 } 117 118 // ToDo: optimize parameter handling 119 func (r *RunConfig) getStepConfig(config *Config, stageName, stepName string, filters map[string]StepFilters, 120 parameters map[string][]StepParameters, secrets map[string][]StepSecrets, stepAliases map[string][]Alias) (StepConfig, error) { 121 // no support for flag values and envParameters 122 // so far not considered necessary 123 124 flagValues := map[string]interface{}{} // args of step from pipeline_generated.yml 125 126 envParameters := map[string]interface{}{} 127 128 // parameters via paramJSON not supported 129 // not considered releavant for pipeline yaml syntax resolution 130 paramJSON := "" 131 132 stepMeta := StepData{ 133 Spec: StepSpec{ 134 Inputs: StepInputs{Parameters: parameters[stepName], Secrets: secrets[stepName]}, 135 }, 136 Metadata: StepMetadata{Aliases: stepAliases[stepName]}, 137 } 138 139 return config.GetStepConfig(flagValues, paramJSON, nil, nil, false, filters[stepName], stepMeta, envParameters, stageName, stepName) 140 } 141 142 func (r *RunConfig) loadConditions() error { 143 defer r.StageConfigFile.Close() 144 content, err := io.ReadAll(r.StageConfigFile) 145 if err != nil { 146 return errors.Wrapf(err, "error: failed to read the stageConfig file") 147 } 148 149 err = yaml.Unmarshal(content, &r.StageConfig) 150 if err != nil { 151 return errors.Errorf("format of configuration is invalid %q: %v", content, err) 152 } 153 return nil 154 } 155 156 // LoadConditionsV1 loads stage conditions (in CRD-style) into PipelineConfig 157 func (r *RunConfigV1) LoadConditionsV1() error { 158 defer r.StageConfigFile.Close() 159 content, err := io.ReadAll(r.StageConfigFile) 160 if err != nil { 161 return errors.Wrapf(err, "error: failed to read the stageConfig file") 162 } 163 164 err = yaml.Unmarshal(content, &r.PipelineConfig) 165 if err != nil { 166 return errors.Errorf("format of configuration is invalid %q: %v", content, err) 167 } 168 return nil 169 } 170 171 func stepConfigLookup(m map[string]interface{}, stepName, key string) interface{} { 172 // flat map: key is on top level 173 if m[key] != nil { 174 return m[key] 175 } 176 // lookup for step config with following format 177 // general: 178 // <key>: <value> 179 // stages: 180 // <stepName>: 181 // <key>: <value> 182 // steps: 183 // <stepName>: 184 // <key>: <value> 185 if m["general"] != nil { 186 general := m["general"].(map[string]interface{}) 187 if general[key] != nil { 188 return general[key] 189 } 190 } 191 if m["stages"] != nil { 192 stages := m["stages"].(map[string]interface{}) 193 if stages[stepName] != nil { 194 stageStepConfig := stages[stepName].(map[string]interface{}) 195 if stageStepConfig[key] != nil { 196 return stageStepConfig[key] 197 } 198 } 199 } 200 if m["steps"] != nil { 201 steps := m["steps"].(map[string]interface{}) 202 if steps[stepName] != nil { 203 stepConfig := steps[stepName].(map[string]interface{}) 204 if stepConfig[key] != nil { 205 return stepConfig[key] 206 } 207 } 208 } 209 return nil 210 }