templater/jobs/utils.go (171 lines of code) (raw):

package jobs import ( "bytes" "fmt" "os" "path/filepath" "strings" "text/template" "github.com/aws/eks-distro-prow-jobs/templater/jobs/types" "github.com/ghodss/yaml" ) var releaseBranches = []string{ "1-28", "1-29", "1-30", "1-31", "1-32", } func GetJobsByType(repos []string, jobType string) (map[string]map[string]types.JobConfig, error) { jobsListByType := map[string]map[string]types.JobConfig{} for _, repo := range repos { jobDir := filepath.Join("jobs", jobType, repo) jobList, err := UnmarshalJobs(jobDir) if err != nil { return nil, fmt.Errorf("reading job directory %s: %v", jobDir, err) } jobsListByType[fmt.Sprintf("aws/%s", repo)] = jobList } return jobsListByType, nil } func AppendMap(current, new map[string]interface{}) map[string]interface{} { newMap := map[string]interface{}{} for k, v := range current { newMap[k] = v } for k, v := range new { newMap[k] = v } return newMap } func AddReleaseBranch(fileName string, data map[string]interface{}) map[string]map[string]interface{} { jobList := map[string]map[string]interface{}{} if !strings.Contains(fileName, "1-X") { return jobList } for i, releaseBranch := range releaseBranches { releaseBranchBasedFileName := strings.ReplaceAll(fileName, "1-X", releaseBranch) otherReleaseBranches := append(append([]string{}, releaseBranches[:i]...), releaseBranches[i+1:]...) jobList[releaseBranchBasedFileName] = AppendMap(data, map[string]interface{}{ "releaseBranch": releaseBranch, "otherReleaseBranches": strings.Join(otherReleaseBranches, "|"), }) // If latest release branch, check if the release branch dir exists before executing cmd // This allows us to experiment with adding prow jobs for new branches without failing other runs if len(releaseBranches)-1 == i { jobList[releaseBranchBasedFileName]["latestReleaseBranch"] = true } } return jobList } func RunMappers(jobsToData map[string]map[string]interface{}, mappers []func(string, map[string]interface{}) map[string]map[string]interface{}) { if len(mappers) == 0 { return } for fileName, data := range jobsToData { newJobList := mappers[0](fileName, data) if len(newJobList) == 0 { continue } for k, v := range newJobList { jobsToData[k] = v if _, ok := data["templateFileName"]; !ok { jobsToData[k]["templateFileName"] = fileName } } delete(jobsToData, fileName) } RunMappers(jobsToData, mappers[1:]) } func UnmarshalJobs(jobDir string) (map[string]types.JobConfig, error) { files, err := os.ReadDir(jobDir) if err != nil { return nil, fmt.Errorf("reading job directory %s: %v", jobDir, err) } var mappers []func(string, map[string]interface{}) map[string]map[string]interface{} mappers = append(mappers, AddReleaseBranch) jobsToData := map[string]map[string]interface{}{} for _, file := range files { jobsToData[file.Name()] = map[string]interface{}{} } RunMappers(jobsToData, mappers) finalJobList := map[string]types.JobConfig{} for fileName, data := range jobsToData { templateFileName := fileName if name, ok := data["templateFileName"]; ok { templateFileName = name.(string) } jobConfig, err := GenerateJobConfig(data, filepath.Join(jobDir, templateFileName)) if err != nil { return nil, fmt.Errorf("%v", err) } if latest, ok := data["latestReleaseBranch"]; ok && latest.(bool) { for j, command := range jobConfig.Commands { jobConfig.Commands[j] = "if make check-for-supported-release-branch -C $PROJECT_PATH; then " + command + "; fi" } } finalJobList[fileName] = jobConfig } return finalJobList, nil } func ExecuteTemplate(templateContent string, data interface{}) ([]byte, error) { temp := template.New("template") funcMap := map[string]interface{}{ "indent": func(spaces int, v string) string { pad := strings.Repeat(" ", spaces) return pad + strings.Replace(v, "\n", "\n"+pad, -1) }, "stringsJoin": strings.Join, "trim": strings.TrimSpace, } temp = temp.Funcs(funcMap) temp, err := temp.Parse(templateContent) if err != nil { return nil, fmt.Errorf("parsing template: %v", err) } var buf bytes.Buffer err = temp.Execute(&buf, data) if err != nil { return nil, fmt.Errorf("substituting values for template: %v", err) } return buf.Bytes(), nil } func GenerateJobConfig(data interface{}, filePath string) (types.JobConfig, error) { var jobConfig types.JobConfig contents, err := os.ReadFile(filePath) if err != nil { return jobConfig, fmt.Errorf("reading job YAML %s: %v", filePath, err) } var templatedContents []byte if data != nil { templatedContents, err = ExecuteTemplate(string(contents), data) if err != nil { return jobConfig, fmt.Errorf("executing template: %v", err) } err = yaml.Unmarshal(templatedContents, &jobConfig) if err != nil { return jobConfig, fmt.Errorf("unmarshaling contents of file %s: %v", filePath, err) } } else { err = yaml.Unmarshal(contents, &jobConfig) if err != nil { return jobConfig, fmt.Errorf("unmarshaling contents of file %s: %v", filePath, err) } } return jobConfig, nil } func IsCuratedPackagesPresubmit(config string) bool { return strings.Contains(config, "autoscaler") || strings.Contains(config, "cloud-provider-aws") || strings.Contains(config, "harbor") || strings.Contains(config, "prometheus") || config == "aws-otel-collector-tooling-presubmit" || config == "distribution-tooling-presubmit" || config == "eks-anywhere-packages-image-tooling-presubmit" || config == "emissary-tooling-presubmit" || config == "hello-eks-anywhere-tooling-presubmit" || config == "metallb-tooling-presubmit" || config == "metrics-server-presubmit" || config == "redis-tooling-presubmit" || config == "rolesanywhere-credential-helper-presubmit" || config == "trivy-tooling-presubmit" }