diff --git a/releng/release-tool/BUILD.bazel b/releng/release-tool/BUILD.bazel index 496a9528f0..348cfc8346 100644 --- a/releng/release-tool/BUILD.bazel +++ b/releng/release-tool/BUILD.bazel @@ -8,6 +8,7 @@ go_library( deps = [ "@com_github_google_go_github_v32//github:go_default_library", "@com_github_masterminds_semver//:go_default_library", + "@io_k8s_sigs_yaml//:go_default_library", "@org_golang_x_oauth2//:go_default_library", ], ) diff --git a/releng/release-tool/release-tool.go b/releng/release-tool/release-tool.go index 4fa5eb9852..feb766d08d 100644 --- a/releng/release-tool/release-tool.go +++ b/releng/release-tool/release-tool.go @@ -14,10 +14,10 @@ import ( "strings" "time" - "golang.org/x/oauth2" - "github.com/Masterminds/semver" "github.com/google/go-github/v32/github" + "golang.org/x/oauth2" + "sigs.k8s.io/yaml" ) type blockerListCacheEntry struct { @@ -414,8 +414,14 @@ func (r *releaseData) forkProwJobs() error { // create new prow configs if they don't already exist if _, err := os.Stat(fullOutputConfig); err != nil && os.IsNotExist(err) { + updateJobConfig, err := updatePhase2Jobs(r.org+"/"+r.repo, fullJobConfig) + if err != nil { + return err + } + defer os.Remove(updateJobConfig) + log.Printf("Creating new prow yaml at path %s", fullOutputConfig) - cmd := exec.Command("/usr/bin/config-forker", "--job-config", fullJobConfig, "--version", version, "--output", fullOutputConfig) + cmd := exec.Command("/usr/bin/config-forker", "--job-config", updateJobConfig, "--version", version, "--output", fullOutputConfig) bytes, err := cmd.CombinedOutput() if err != nil { log.Printf("ERROR: config-forker command output: %s : %s ", string(bytes), err) @@ -1271,3 +1277,102 @@ func main() { } } } + +func updatePhase2Jobs(orgRepo, fullJobConfig string) (string, error) { + fileContent, err := ioutil.ReadFile(fullJobConfig) + if err != nil { + return "", fmt.Errorf("Error reading yaml file: %v", err) + } + + var data map[string]interface{} + if err := yaml.Unmarshal(fileContent, &data); err != nil { + return "", fmt.Errorf("Error unmarshalling yaml: %v", err) + } + + jobs, err := detectPhase2Jobs(orgRepo, data) + for _, job := range jobs { + err := updateJob(orgRepo, job, data) + if err != nil { + return "", err + } + } + + updatedContent, err := yaml.Marshal(data) + if err != nil { + return "", fmt.Errorf("Error marshalling yaml: %v", err) + } + + // TODO rand name + updateJobConfig := os.TempDir() + "/job-config.yaml" + if err := ioutil.WriteFile(updateJobConfig, updatedContent, 0644); err != nil { + return "", fmt.Errorf("Error writing updated yaml to file: %v", err) + } + + return updateJobConfig, nil +} + +func updateJob(orgRepo, jobName string, data map[string]interface{}) error { + presubmits, ok := data["presubmits"].(map[string]interface{}) + if !ok { + return fmt.Errorf("Missing or invalid 'presubmits' section in yaml") + } + + repo, ok := presubmits[orgRepo].([]interface{}) + if !ok { + return fmt.Errorf("Missing or invalid section for repository '%s' in yaml", orgRepo) + } + + for i, job := range repo { + jobMap, ok := job.(map[string]interface{}) + if !ok { + return fmt.Errorf("Invalid job format in yaml") + } + + name, ok := jobMap["name"].(string) + if !ok { + return fmt.Errorf("Missing or invalid 'name' field for job in yaml") + } + + if name == jobName { + jobMap["always_run"] = true + presubmits[orgRepo].([]interface{})[i] = jobMap + return nil + } + } + + return fmt.Errorf("Error job wasn't found: %v", jobName) +} + +func detectPhase2Jobs(orgRepo string, data map[string]interface{}) ([]string, error) { + presubmits, ok := data["presubmits"].(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("Missing or invalid 'presubmits' section in yaml") + } + + repo, ok := presubmits[orgRepo].([]interface{}) + if !ok { + return nil, fmt.Errorf("Missing or invalid section for repository '%s' in yaml", orgRepo) + } + + jobs := []string{} + for _, job := range repo { + jobMap, ok := job.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("Invalid job format in yaml") + } + + optional, optionalOk := jobMap["optional"].(bool) + alwaysRun, alwaysRunOk := jobMap["always_run"].(bool) + runIfChanged, runIfChangedOk := jobMap["run_if_changed"].(string) + skipIfOnlyChanged, skipIfOnlyChangedOk := jobMap["skip_if_only_changed"].(string) + + if (!alwaysRunOk || !alwaysRun) && + (!optionalOk || !optional) && + (!runIfChangedOk || runIfChanged == "") && + (!skipIfOnlyChangedOk || skipIfOnlyChanged == "") { + jobs = append(jobs, jobMap["name"].(string)) + } + } + + return jobs, nil +}