github.com/diggerhq/digger/libs@v0.0.0-20240604170430-9d61cdf01cc5/digger_config/yaml.go (about)

     1  package digger_config
     2  
     3  import (
     4  	"errors"
     5  
     6  	"gopkg.in/yaml.v3"
     7  )
     8  
     9  type DiggerConfigYaml struct {
    10  	ApplyAfterMerge            *bool                        `yaml:"apply_after_merge"`
    11  	AllowDraftPRs              *bool                        `yaml:"allow_draft_prs"`
    12  	DependencyConfiguration    *DependencyConfigurationYaml `yaml:"dependency_configuration"`
    13  	Projects                   []*ProjectYaml               `yaml:"projects"`
    14  	AutoMerge                  *bool                        `yaml:"auto_merge"`
    15  	CommentRenderMode          *string                      `yaml:"comment_render_mode"`
    16  	Workflows                  map[string]*WorkflowYaml     `yaml:"workflows"`
    17  	Telemetry                  *bool                        `yaml:"telemetry,omitempty"`
    18  	GenerateProjectsConfig     *GenerateProjectsConfigYaml  `yaml:"generate_projects"`
    19  	TraverseToNestedProjects   *bool                        `yaml:"traverse_to_nested_projects"`
    20  	MentionDriftedProjectsInPR *bool                        `yaml:"mention_drifted_projects_in_pr"`
    21  }
    22  
    23  type DependencyConfigurationYaml struct {
    24  	Mode string `yaml:"mode"`
    25  }
    26  
    27  type ProjectYaml struct {
    28  	Name               string                      `yaml:"name"`
    29  	Dir                string                      `yaml:"dir"`
    30  	Workspace          string                      `yaml:"workspace"`
    31  	Terragrunt         bool                        `yaml:"terragrunt"`
    32  	OpenTofu           bool                        `yaml:"opentofu"`
    33  	Workflow           string                      `yaml:"workflow"`
    34  	WorkflowFile       *string                     `yaml:"workflow_file""`
    35  	IncludePatterns    []string                    `yaml:"include_patterns,omitempty"`
    36  	ExcludePatterns    []string                    `yaml:"exclude_patterns,omitempty"`
    37  	DependencyProjects []string                    `yaml:"depends_on,omitempty"`
    38  	DriftDetection     *bool                       `yaml:"drift_detection,omitempty"`
    39  	AwsRoleToAssume    *AssumeRoleForProjectConfig `yaml:"aws_role_to_assume,omitempty"`
    40  }
    41  
    42  type WorkflowYaml struct {
    43  	EnvVars       *TerraformEnvConfigYaml    `yaml:"env_vars"`
    44  	Plan          *StageYaml                 `yaml:"plan,omitempty"`
    45  	Apply         *StageYaml                 `yaml:"apply,omitempty"`
    46  	Configuration *WorkflowConfigurationYaml `yaml:"workflow_configuration"`
    47  }
    48  
    49  type WorkflowConfigurationYaml struct {
    50  	OnPullRequestPushed []string `yaml:"on_pull_request_pushed"`
    51  	OnPullRequestClosed []string `yaml:"on_pull_request_closed"`
    52  	// pull request converted to draft
    53  	OnPullRequestConvertedToDraft []string `yaml:"on_pull_request_to_draft"`
    54  	OnCommitToDefault             []string `yaml:"on_commit_to_default"`
    55  }
    56  
    57  func (s *StageYaml) ToCoreStage() Stage {
    58  	var steps []Step
    59  	for _, step := range s.Steps {
    60  		steps = append(steps, step.ToCoreStep())
    61  	}
    62  	return Stage{Steps: steps}
    63  }
    64  
    65  type StageYaml struct {
    66  	Steps []StepYaml `yaml:"steps"`
    67  }
    68  
    69  type StepYaml struct {
    70  	Action    string
    71  	Value     string
    72  	ExtraArgs []string `yaml:"extra_args,omitempty"`
    73  	Shell     string
    74  }
    75  
    76  type TerraformEnvConfigYaml struct {
    77  	State    []EnvVarYaml `yaml:"state"`
    78  	Commands []EnvVarYaml `yaml:"commands"`
    79  }
    80  
    81  type EnvVarYaml struct {
    82  	Name      string `yaml:"name"`
    83  	ValueFrom string `yaml:"value_from"`
    84  	Value     string `yaml:"value"`
    85  }
    86  
    87  type BlockYaml struct {
    88  	Include         string                      `yaml:"include"`
    89  	Exclude         string                      `yaml:"exclude"`
    90  	Workflow        string                      `yaml:"workflow"`
    91  	AwsRoleToAssume *AssumeRoleForProjectConfig `yaml:"aws_role_to_assume,omitempty"`
    92  }
    93  
    94  type AssumeRoleForProjectConfig struct {
    95  	AwsRoleRegion string `yaml:"aws_role_region"`
    96  	State         string `yaml:"state"`
    97  	Command       string `yaml:"command"`
    98  }
    99  
   100  type GenerateProjectsConfigYaml struct {
   101  	Include                 string                      `yaml:"include"`
   102  	Exclude                 string                      `yaml:"exclude"`
   103  	Terragrunt              bool                        `yaml:"terragrunt"`
   104  	Blocks                  []BlockYaml                 `yaml:"blocks"`
   105  	TerragruntParsingConfig *TerragruntParsingConfig    `yaml:"terragrunt_parsing,omitempty"`
   106  	AwsRoleToAssume         *AssumeRoleForProjectConfig `yaml:"aws_role_to_assume,omitempty"`
   107  }
   108  
   109  type TerragruntParsingConfig struct {
   110  	GitRoot                  *string  `yaml:"gitRoot,omitempty"`
   111  	AutoPlan                 bool     `yaml:"autoPlan"`
   112  	AutoMerge                bool     `yaml:"autoMerge"`
   113  	IgnoreParentTerragrunt   *bool    `yaml:"ignoreParentTerragrunt,omitempty"`
   114  	CreateParentProject      bool     `yaml:"createParentProject"`
   115  	IgnoreDependencyBlocks   bool     `yaml:"ignoreDependencyBlocks"`
   116  	Parallel                 *bool    `yaml:"parallel,omitempty"`
   117  	CreateWorkspace          bool     `yaml:"createWorkspace"`
   118  	CreateProjectName        bool     `yaml:"createProjectName"`
   119  	DefaultTerraformVersion  string   `yaml:"defaultTerraformVersion"`
   120  	DefaultWorkflow          string   `yaml:"defaultWorkflow"`
   121  	FilterPath               string   `yaml:"filterPath"`
   122  	OutputPath               string   `yaml:"outputPath"`
   123  	PreserveWorkflows        *bool    `yaml:"preserveWorkflows,omitempty"`
   124  	PreserveProjects         bool     `yaml:"preserveProjects"`
   125  	CascadeDependencies      *bool    `yaml:"cascadeDependencies,omitempty"`
   126  	DefaultApplyRequirements []string `yaml:"defaultApplyRequirements"`
   127  	//NumExecutors                   int64	`yaml:"numExecutors"`
   128  	ProjectHclFiles                []string `yaml:"projectHclFiles"`
   129  	CreateHclProjectChilds         bool     `yaml:"createHclProjectChilds"`
   130  	CreateHclProjectExternalChilds *bool    `yaml:"createHclProjectExternalChilds,omitempty"`
   131  	UseProjectMarkers              bool     `yaml:"useProjectMarkers"`
   132  	ExecutionOrderGroups           *bool    `yaml:"executionOrderGroups"`
   133  }
   134  
   135  func (p *ProjectYaml) UnmarshalYAML(unmarshal func(interface{}) error) error {
   136  	type rawProject ProjectYaml
   137  	raw := rawProject{
   138  		Workspace:  "default",
   139  		Terragrunt: false,
   140  		Workflow:   "default",
   141  	}
   142  	if err := unmarshal(&raw); err != nil {
   143  		return err
   144  	}
   145  	*p = ProjectYaml(raw)
   146  	return nil
   147  }
   148  
   149  func (w *WorkflowYaml) UnmarshalYAML(unmarshal func(interface{}) error) error {
   150  	type rawWorkflow WorkflowYaml
   151  	raw := rawWorkflow{
   152  		Configuration: &WorkflowConfigurationYaml{
   153  			OnCommitToDefault:   []string{"digger unlock"},
   154  			OnPullRequestPushed: []string{"digger plan"},
   155  			OnPullRequestClosed: []string{"digger unlock"},
   156  		},
   157  		Plan: &StageYaml{
   158  			Steps: []StepYaml{
   159  				{
   160  					Action: "init", ExtraArgs: []string{},
   161  				},
   162  				{
   163  					Action: "plan", ExtraArgs: []string{},
   164  				},
   165  			},
   166  		},
   167  		Apply: &StageYaml{
   168  			Steps: []StepYaml{
   169  				{
   170  					Action: "init", ExtraArgs: []string{},
   171  				},
   172  				{
   173  					Action: "apply", ExtraArgs: []string{},
   174  				},
   175  			},
   176  		},
   177  		EnvVars: &TerraformEnvConfigYaml{
   178  			State:    []EnvVarYaml{},
   179  			Commands: []EnvVarYaml{},
   180  		},
   181  	}
   182  	if err := unmarshal(&raw); err != nil {
   183  		return err
   184  	}
   185  	if err := validateWorkflowConfigurationYaml(raw.Configuration); err != nil {
   186  		return err
   187  	}
   188  	*w = WorkflowYaml(raw)
   189  	return nil
   190  }
   191  
   192  func validateWorkflowConfigurationYaml(config *WorkflowConfigurationYaml) error {
   193  	if config != nil {
   194  		if config.OnPullRequestPushed == nil {
   195  			return errors.New("workflow_configuration.on_pull_request_pushed is required")
   196  		}
   197  		if config.OnPullRequestClosed == nil {
   198  			return errors.New("workflow_configuration.on_pull_request_closed is required")
   199  		}
   200  		if config.OnCommitToDefault == nil {
   201  			return errors.New("workflow_configuration.on_commit_to_default is required")
   202  		}
   203  	}
   204  	return nil
   205  }
   206  
   207  func (s *StepYaml) UnmarshalYAML(value *yaml.Node) error {
   208  
   209  	if value.Kind == yaml.ScalarNode {
   210  		return value.Decode(&s.Action)
   211  	}
   212  
   213  	var stepMap map[string]interface{}
   214  	if err := value.Decode(&stepMap); err != nil {
   215  		return err
   216  	}
   217  
   218  	if _, ok := stepMap["run"]; ok {
   219  		s.Action = "run"
   220  		s.Value = stepMap["run"].(string)
   221  		if _, ok := stepMap["shell"]; ok {
   222  			s.Shell = stepMap["shell"].(string)
   223  		}
   224  		return nil
   225  	}
   226  
   227  	s.extract(stepMap, "init")
   228  	s.extract(stepMap, "plan")
   229  	s.extract(stepMap, "apply")
   230  
   231  	return nil
   232  }
   233  
   234  func (s *StepYaml) ToCoreStep() Step {
   235  	return Step{
   236  		Action:    s.Action,
   237  		Value:     s.Value,
   238  		ExtraArgs: s.ExtraArgs,
   239  		Shell:     s.Shell,
   240  	}
   241  }
   242  
   243  func (s *StepYaml) extract(stepMap map[string]interface{}, action string) {
   244  	if _, ok := stepMap[action]; ok {
   245  		s.Action = action
   246  		var extraArgs []string
   247  		if v, ok := stepMap["extra_args"]; ok {
   248  			for _, v := range v.([]interface{}) {
   249  				extraArgs = append(extraArgs, v.(string))
   250  			}
   251  			s.ExtraArgs = extraArgs
   252  		} else {
   253  			if stepMap[action] != nil {
   254  				if v, ok := stepMap[action].(map[string]interface{})["extra_args"]; ok {
   255  					for _, v := range v.([]interface{}) {
   256  						extraArgs = append(extraArgs, v.(string))
   257  					}
   258  					s.ExtraArgs = extraArgs
   259  				}
   260  			}
   261  		}
   262  	}
   263  }