github.com/jaylevin/jenkins-library@v1.230.4/pkg/config/run.go (about)

     1  package config
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"io/ioutil"
     7  
     8  	"github.com/SAP/jenkins-library/pkg/piperutils"
     9  	"github.com/ghodss/yaml"
    10  	"github.com/pkg/errors"
    11  )
    12  
    13  // RunConfig ...
    14  type RunConfig struct {
    15  	StageConfigFile io.ReadCloser
    16  	StageConfig     StageConfig
    17  	RunStages       map[string]bool
    18  	RunSteps        map[string]map[string]bool
    19  	OpenFile        func(s string, t map[string]string) (io.ReadCloser, error)
    20  	FileUtils       *piperutils.Files
    21  }
    22  
    23  type RunConfigV1 struct {
    24  	RunConfig
    25  	PipelineConfig PipelineDefinitionV1
    26  }
    27  
    28  type StageConfig struct {
    29  	Stages map[string]StepConditions `json:"stages,omitempty"`
    30  }
    31  
    32  type StepConditions struct {
    33  	Conditions map[string]map[string]interface{} `json:"stepConditions,omitempty"`
    34  }
    35  
    36  type PipelineDefinitionV1 struct {
    37  	APIVersion string   `json:"apiVersion"`
    38  	Kind       string   `json:"kind"`
    39  	Metadata   Metadata `json:"metadata"`
    40  	Spec       Spec     `json:"spec"`
    41  	openFile   func(s string, t map[string]string) (io.ReadCloser, error)
    42  	runSteps   map[string]map[string]bool
    43  }
    44  
    45  type Metadata struct {
    46  	Name        string `json:"name,omitempty"`
    47  	DisplayName string `json:"displayName,omitempty"`
    48  	Description string `json:"description,omitempty"`
    49  }
    50  
    51  type Spec struct {
    52  	Stages []Stage `json:"stages"`
    53  }
    54  
    55  type Stage struct {
    56  	Name        string `json:"name,omitempty"`
    57  	DisplayName string `json:"displayName,omitempty"`
    58  	Description string `json:"description,omitempty"`
    59  	Steps       []Step `json:"steps,omitempty"`
    60  }
    61  
    62  type Step struct {
    63  	Name                string          `json:"name,omitempty"`
    64  	Description         string          `json:"description,omitempty"`
    65  	Conditions          []StepCondition `json:"conditions,omitempty"`
    66  	NotActiveConditions []StepCondition `json:"notActiveConditions,omitempty"`
    67  	Orchestrators       []string        `json:"orchestrators,omitempty"`
    68  }
    69  
    70  type StepCondition struct {
    71  	Config                    map[string][]interface{} `json:"config,omitempty"`
    72  	ConfigKey                 string                   `json:"configKey,omitempty"`
    73  	FilePattern               string                   `json:"filePattern,omitempty"`
    74  	FilePatternFromConfig     string                   `json:"filePatternFromConfig,omitempty"`
    75  	Inactive                  bool                     `json:"inactive,omitempty"`
    76  	NpmScript                 string                   `json:"npmScript,omitempty"`
    77  	CommonPipelineEnvironment map[string]interface{}   `json:"commonPipelineEnvironment,omitempty"`
    78  }
    79  
    80  func (r *RunConfigV1) InitRunConfigV1(config *Config, filters map[string]StepFilters, parameters map[string][]StepParameters,
    81  	secrets map[string][]StepSecrets, stepAliases map[string][]Alias, 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, filters, parameters, secrets, stepAliases, 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 := ioutil.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 := ioutil.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  }