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 // Update Go Dependencies. 109 if b.extraConfig("UpdateGoDeps") { 110 b.updateGoDeps() 111 return 112 } 113 114 // Create docker image. 115 if b.extraConfig("CreateDockerImage") { 116 b.createDockerImage(b.extraConfig("WASM")) 117 return 118 } 119 120 // Push apps from docker image. 121 if b.extraConfig("PushAppsFromSkiaDockerImage") { 122 b.createPushAppsFromSkiaDockerImage() 123 return 124 } else if b.extraConfig("PushAppsFromWASMDockerImage") { 125 b.createPushAppsFromWASMDockerImage() 126 return 127 } 128 129 // Infra tests. 130 if b.extraConfig("InfraTests") { 131 b.infra() 132 return 133 } 134 135 // Housekeepers. 136 if b.Name == "Housekeeper-PerCommit" { 137 b.housekeeper() 138 return 139 } 140 if b.Name == "Housekeeper-PerCommit-CheckGeneratedFiles" { 141 b.checkGeneratedFiles() 142 return 143 } 144 if b.Name == "Housekeeper-PerCommit-RunGnToBp" { 145 b.checkGnToBp() 146 return 147 } 148 if b.Name == "Housekeeper-OnDemand-Presubmit" { 149 b.priority(1) 150 b.presubmit() 151 return 152 } 153 154 // Compile bots. 155 if b.role("Build") { 156 b.compile() 157 return 158 } 159 160 // BuildStats bots. This computes things like binary size. 161 if b.role("BuildStats") { 162 b.buildstats() 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 if b.role("FM") { 184 b.fm() 185 return 186 } 187 188 // Canary bots. 189 if b.role("Canary") { 190 if b.project("G3") { 191 b.g3FrameworkCanary() 192 return 193 } else if b.project("Android") { 194 b.canary("android-master-autoroll") 195 return 196 } else if b.project("Chromium") { 197 b.canary("skia-autoroll") 198 return 199 } else if b.project("Flutter") { 200 b.canary("skia-flutter-autoroll") 201 return 202 } 203 } 204 205 if b.extraConfig("Puppeteer") { 206 // TODO(kjlubick) make this a new role 207 b.puppeteer() 208 return 209 } 210 211 // Perf bots. 212 if b.role("Perf") { 213 b.perf() 214 return 215 } 216 217 // Fuzz bots (aka CIFuzz). See 218 // https://google.github.io/oss-fuzz/getting-started/continuous-integration/ for more. 219 if b.role("Fuzz") { 220 b.cifuzz() 221 return 222 } 223 224 log.Fatalf("Don't know how to handle job %q", b.Name) 225} 226 227func (b *jobBuilder) finish() { 228 // Add the Job spec. 229 if b.frequency("Nightly") { 230 b.trigger(specs.TRIGGER_NIGHTLY) 231 } else if b.frequency("Weekly") { 232 b.trigger(specs.TRIGGER_WEEKLY) 233 } else if b.extraConfig("Flutter", "CommandBuffer") { 234 b.trigger(specs.TRIGGER_MASTER_ONLY) 235 } else if b.frequency("OnDemand") || b.role("Canary") { 236 b.trigger(specs.TRIGGER_ON_DEMAND) 237 } else { 238 b.trigger(specs.TRIGGER_ANY_BRANCH) 239 } 240 b.MustAddJob(b.Name, b.Spec) 241} 242