github.com/devtron-labs/ci-runner@v0.0.0-20240518055909-b2672f3349d7/helper/YamlTaskHelper.go (about) 1 /* 2 * Copyright 2020 Devtron Labs 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 */ 17 18 package helper 19 20 import ( 21 "errors" 22 "io/ioutil" 23 "log" 24 "os" 25 "path/filepath" 26 "regexp" 27 28 "github.com/devtron-labs/ci-runner/util" 29 "gopkg.in/yaml.v2" 30 ) 31 32 type Task struct { 33 Id int `json:"id"` 34 Index int `json:"index"` 35 Name string `json:"name" yaml:"name"` 36 Script string `json:"script" yaml:"script"` 37 OutputLocation string `json:"outputLocation" yaml:"outputLocation"` // file/dir 38 RunStatus bool `json:"-"` // task run was attempted or not 39 } 40 41 type TaskYaml struct { 42 Version string `yaml:"version"` 43 PipelineConf []PipelineConfig `yaml:"pipelineConf"` 44 CdPipelineConfig []CdPipelineConfig `yaml:"cdPipelineConf"` 45 } 46 47 type PipelineConfig struct { 48 AppliesTo []AppliesTo `yaml:"appliesTo"` 49 BeforeTasks []*Task `yaml:"beforeDockerBuildStages"` 50 AfterTasks []*Task `yaml:"afterDockerBuildStages"` 51 } 52 53 type CdPipelineConfig struct { 54 BeforeTasks []*Task `yaml:"beforeStages"` 55 AfterTasks []*Task `yaml:"afterStages"` 56 } 57 58 type AppliesTo struct { 59 Type string `yaml:"type"` 60 Value []string `yaml:"value"` 61 } 62 63 const BRANCH_FIXED = "BRANCH_FIXED" 64 65 func GetBeforeDockerBuildTasks(ciRequest *CommonWorkflowRequest, taskYaml *TaskYaml) ([]*Task, error) { 66 if taskYaml == nil { 67 log.Println(util.DEVTRON, "no tasks, devtron-ci yaml missing") 68 return nil, nil 69 } 70 71 if taskYaml.Version != "0.0.1" { 72 log.Println("invalid version for devtron-ci.yaml") 73 return nil, errors.New("invalid version for devtron-ci.yaml") 74 } 75 76 pipelineConfig := taskYaml.PipelineConf 77 log.Println(util.DEVTRON, "pipelineConf length: ", len(pipelineConfig)) 78 79 var tasks []*Task 80 filteredOut := false 81 for _, p := range pipelineConfig { 82 if filteredOut { 83 break 84 } 85 for _, a := range p.AppliesTo { 86 triggerType := a.Type 87 if triggerType == BRANCH_FIXED { 88 branches := a.Value 89 branchesMap := make(map[string]bool) 90 for _, b := range branches { 91 branchesMap[b] = true 92 } 93 if !isValidBranch(ciRequest, a) { 94 log.Println(util.DEVTRON, "skipping current AppliesTo") 95 continue 96 } 97 tasks = append(tasks, p.BeforeTasks...) 98 filteredOut = true 99 } else { 100 log.Println(util.DEVTRON, "unknown triggerType ", triggerType) 101 } 102 } 103 104 } 105 return tasks, nil 106 } 107 108 func GetAfterDockerBuildTasks(ciRequest *CommonWorkflowRequest, taskYaml *TaskYaml) ([]*Task, error) { 109 if taskYaml == nil { 110 log.Println(util.DEVTRON, "no tasks, devtron-ci yaml missing") 111 return nil, nil 112 } 113 114 if taskYaml.Version != "0.0.1" { // TODO: Get version from ciRequest based on ci_pipeline 115 log.Println("invalid version for devtron-ci.yaml") 116 return nil, errors.New("invalid version for devtron-ci.yaml") 117 } 118 119 pipelineConfig := taskYaml.PipelineConf 120 log.Println(util.DEVTRON, "pipelineConf length: ", len(pipelineConfig)) 121 122 var tasks []*Task 123 filteredOut := false 124 for _, p := range pipelineConfig { 125 if filteredOut { 126 break 127 } 128 for _, a := range p.AppliesTo { 129 triggerType := a.Type 130 if triggerType == BRANCH_FIXED { 131 isValidSourceType := true 132 for _, p := range ciRequest.CiProjectDetails { 133 // SOURCE_TYPE_WEBHOOK is not yet supported for pre-ci-stages. so handling here to get rid of fatal 134 if p.SourceType != SOURCE_TYPE_BRANCH_FIXED && p.SourceType != SOURCE_TYPE_WEBHOOK { 135 log.Println(util.DEVTRON, "skipping invalid source type") 136 isValidSourceType = false 137 break 138 } 139 } 140 if isValidSourceType { 141 if !isValidBranch(ciRequest, a) { 142 log.Println(util.DEVTRON, "skipping current AppliesTo") 143 continue 144 } 145 tasks = append(tasks, p.AfterTasks...) 146 filteredOut = true 147 } 148 } else { 149 log.Println(util.DEVTRON, "unknown triggerType ", triggerType) 150 } 151 } 152 } 153 return tasks, nil 154 } 155 156 func isValidBranch(ciRequest *CommonWorkflowRequest, a AppliesTo) bool { 157 branches := a.Value 158 branchesMap := make(map[string]bool) 159 for _, b := range branches { 160 branchesMap[b] = true 161 } 162 isValidBranch := true 163 for _, prj := range ciRequest.CiProjectDetails { 164 if _, ok := branchesMap[prj.SourceValue]; !ok { 165 log.Println(util.DEVTRON, "invalid branch") 166 isValidBranch = false 167 break 168 } 169 } 170 return isValidBranch 171 } 172 173 func isValidTag(ciRequest *CommonWorkflowRequest, a AppliesTo) bool { 174 tagsRegex := a.Value 175 for _, prj := range ciRequest.CiProjectDetails { 176 for _, t := range tagsRegex { 177 match, _ := regexp.MatchString(t, prj.GitTag) 178 if match { 179 return true 180 } 181 } 182 } 183 return false 184 } 185 186 func GetTaskYaml(yamlLocation string) (*TaskYaml, error) { 187 filename := filepath.Join(yamlLocation, "devtron-ci.yaml") 188 if _, err := os.Stat(filename); os.IsNotExist(err) { 189 log.Println("file not found", filename) 190 return nil, nil 191 } 192 193 yamlFile, err := ioutil.ReadFile(filename) 194 if err != nil { 195 log.Println(err) 196 return nil, err 197 } 198 199 if yamlFile == nil || string(yamlFile) == "" { 200 log.Println("file not found", filename) 201 return nil, nil 202 } 203 204 taskYaml, err := ToTaskYaml(yamlFile) 205 if err != nil { 206 log.Println(err) 207 return nil, err 208 } 209 210 log.Println("yaml version: ", taskYaml.Version) 211 return taskYaml, nil 212 } 213 214 func ToTaskYaml(yamlFile []byte) (*TaskYaml, error) { 215 taskYaml := &TaskYaml{} 216 err := yaml.Unmarshal(yamlFile, taskYaml) 217 return taskYaml, err 218 }