1// Copyright 2020 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4package gen_tasks_logic 5 6import ( 7 "log" 8 "strings" 9 10 "go.skia.org/infra/task_scheduler/go/specs" 11) 12 13// jobBuilder provides helpers for creating a job. 14type jobBuilder struct { 15 *builder 16 parts 17 Name string 18 Spec *specs.JobSpec 19} 20 21// newJobBuilder returns a jobBuilder for the given job name. 22func newJobBuilder(b *builder, name string) *jobBuilder { 23 p, err := b.jobNameSchema.ParseJobName(name) 24 if err != nil { 25 log.Fatal(err) 26 } 27 return &jobBuilder{ 28 builder: b, 29 parts: p, 30 Name: name, 31 Spec: &specs.JobSpec{}, 32 } 33} 34 35// priority sets the priority of the job. 36func (b *jobBuilder) priority(p float64) { 37 b.Spec.Priority = p 38} 39 40// trigger dictates when the job should be triggered. 41func (b *jobBuilder) trigger(trigger string) { 42 b.Spec.Trigger = trigger 43} 44 45// Create a taskBuilder and run the given function for it. 46func (b *jobBuilder) addTask(name string, fn func(*taskBuilder)) { 47 tb := newTaskBuilder(b, name) 48 fn(tb) 49 b.MustAddTask(tb.Name, tb.Spec) 50 // Add the task to the Job's dependency set, removing any which are 51 // accounted for by the new task's dependencies. 52 b.Spec.TaskSpecs = append(b.Spec.TaskSpecs, tb.Name) 53 newSpecs := make([]string, 0, len(b.Spec.TaskSpecs)) 54 for _, t := range b.Spec.TaskSpecs { 55 if !In(t, tb.Spec.Dependencies) { 56 newSpecs = append(newSpecs, t) 57 } 58 } 59 b.Spec.TaskSpecs = newSpecs 60} 61 62// uploadCIPDAssetToCAS generates a task to isolate the given CIPD asset. Returns 63// the name of the task. 64func (b *jobBuilder) uploadCIPDAssetToCAS(asset string) string { 65 cfg, ok := ISOLATE_ASSET_MAPPING[asset] 66 if !ok { 67 log.Fatalf("No isolate task for asset %q", asset) 68 } 69 b.addTask(cfg.uploadTaskName, func(b *taskBuilder) { 70 b.cipd(b.MustGetCipdPackageFromAsset(asset)) 71 b.cmd("/bin/cp", "-rL", cfg.path, "${ISOLATED_OUTDIR}") 72 b.linuxGceDimensions(MACHINE_TYPE_SMALL) 73 b.idempotent() 74 b.cas(CAS_EMPTY) 75 }) 76 return cfg.uploadTaskName 77} 78 79// genTasksForJob generates the tasks needed by this job. 80func (b *jobBuilder) genTasksForJob() { 81 // Bundle Recipes. 82 if b.Name == BUNDLE_RECIPES_NAME { 83 b.bundleRecipes() 84 return 85 } 86 if strings.HasPrefix(b.Name, BUILD_TASK_DRIVERS_PREFIX) { 87 parts := strings.Split(b.Name, "_") 88 b.buildTaskDrivers(parts[1], parts[2]) 89 return 90 } 91 92 // Isolate CIPD assets. 93 if b.matchExtraConfig("Isolate") { 94 for asset, cfg := range ISOLATE_ASSET_MAPPING { 95 if cfg.uploadTaskName == b.Name { 96 b.uploadCIPDAssetToCAS(asset) 97 return 98 } 99 } 100 } 101 102 // RecreateSKPs. 103 if b.extraConfig("RecreateSKPs") { 104 b.recreateSKPs() 105 return 106 } 107 108 // Create docker image. 109 if b.extraConfig("CreateDockerImage") { 110 b.createDockerImage(b.extraConfig("WASM")) 111 return 112 } 113 114 // Push apps from docker image. 115 if b.extraConfig("PushAppsFromSkiaDockerImage") { 116 b.createPushAppsFromSkiaDockerImage() 117 return 118 } 119 120 // Infra tests. 121 if b.extraConfig("InfraTests") { 122 b.infra() 123 return 124 } 125 126 // Housekeepers. 127 if b.Name == "Housekeeper-PerCommit" { 128 b.housekeeper() 129 return 130 } 131 if b.Name == "Housekeeper-PerCommit-CheckGeneratedFiles" { 132 b.checkGeneratedFiles() 133 return 134 } 135 if b.Name == "Housekeeper-PerCommit-GoLinters" { 136 b.goLinters() 137 return 138 } 139 if b.Name == "Housekeeper-PerCommit-RunGnToBp" { 140 b.checkGnToBp() 141 return 142 } 143 if b.Name == "Housekeeper-OnDemand-Presubmit" { 144 b.priority(1) 145 b.presubmit() 146 return 147 } 148 149 // Compile bots. 150 if b.role("Build") { 151 b.compile() 152 return 153 } 154 155 // BuildStats bots. This computes things like binary size. 156 if b.role("BuildStats") { 157 b.buildstats() 158 return 159 } 160 161 if b.role("CodeSize") { 162 b.codesize() 163 return 164 } 165 166 // Valgrind runs at a low priority so that it doesn't occupy all the bots. 167 if b.extraConfig("Valgrind") { 168 // Priority of 0.085 should result in Valgrind tasks with a blamelist of ~10 commits having the 169 // same score as other tasks with a blamelist of 1 commit, when we have insufficient bot 170 // capacity to run more frequently. 171 b.priority(0.085) 172 } 173 174 // Test bots. 175 if b.role("Test") { 176 if b.extraConfig("WasmGMTests") { 177 b.runWasmGMTests() 178 return 179 } 180 b.dm() 181 return 182 } 183 184 // Canary bots. 185 if b.role("Canary") { 186 if b.project("G3") { 187 b.g3FrameworkCanary() 188 return 189 } else if b.project("Android") { 190 b.canary("android-master-autoroll", "Canary-Android-Topic", "https://googleplex-android-review.googlesource.com/q/topic:") 191 return 192 } else if b.project("Chromium") { 193 b.canary("skia-autoroll", "Canary-Chromium-CL", "https://chromium-review.googlesource.com/c/") 194 return 195 } else if b.project("Flutter") { 196 b.canary("skia-flutter-autoroll", "Canary-Flutter-PR", "https://github.com/flutter/engine/pull/") 197 return 198 } 199 } 200 201 if b.extraConfig("Puppeteer") { 202 // TODO(kjlubick) make this a new role 203 b.puppeteer() 204 return 205 } 206 207 // Perf bots. 208 if b.role("Perf") { 209 b.perf() 210 return 211 } 212 213 if b.role("BazelBuild") { 214 b.bazelBuild() 215 return 216 } 217 218 if b.role("BazelTest") { 219 b.bazelTest() 220 return 221 } 222 223 log.Fatalf("Don't know how to handle job %q", b.Name) 224} 225 226func (b *jobBuilder) finish() { 227 // Add the Job spec. 228 if b.frequency("Nightly") { 229 b.trigger(specs.TRIGGER_NIGHTLY) 230 } else if b.frequency("Weekly") { 231 b.trigger(specs.TRIGGER_WEEKLY) 232 } else if b.extraConfig("Flutter", "CreateDockerImage", "PushAppsFromSkiaDockerImage", "PushBazelAppsFromWASMDockerImage") { 233 b.trigger(specs.TRIGGER_MAIN_ONLY) 234 } else if b.frequency("OnDemand") || b.role("Canary") { 235 b.trigger(specs.TRIGGER_ON_DEMAND) 236 } else { 237 b.trigger(specs.TRIGGER_ANY_BRANCH) 238 } 239 b.MustAddJob(b.Name, b.Spec) 240} 241