1 # Copyright 2017 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. 4 5 # Recipe which: 6 # 1) Extracts all fiddles out of markdown files. 7 # 2) Forces fiddle.skia.org to compile all those fiddles and get output in JSON. 8 # 3) Scans the output and reports any compiletime/runtime errors. 9 # 4) Updates markdown in site/user/api/ using the new hashes (if any) from 10 # fiddle.skia.org. 11 12 import json 13 14 15 DEPS = [ 16 'recipe_engine/context', 17 'recipe_engine/file', 18 'recipe_engine/path', 19 'recipe_engine/properties', 20 'recipe_engine/step', 21 'core', 22 'infra', 23 'run', 24 'vars', 25 ] 26 27 UPDATE_DOCS_GITCOOKIES_FILE = 'update_docs.git_cookies' 28 UPDATE_DOCS_GITCOOKIES_GS_PATH = ( 29 'gs://skia-buildbots/artifacts/server/.gitcookies_update-docs') 30 31 32 def go_get_fiddlecli(api): 33 env = api.context.env 34 env.update(api.infra.go_env) 35 with api.context(env=env): 36 api.run.with_retry( 37 api.step, 38 'go get fiddlecli', 39 5, # Update attempts. 40 cmd=[api.infra.go_exe, 'get', '-u', '-t', 41 'go.skia.org/infra/fiddle/go/fiddlecli']) 42 43 44 def RunSteps(api): 45 api.vars.setup() 46 api.core.checkout_bot_update() 47 api.infra.go_version() 48 go_get_fiddlecli(api) 49 50 with api.context(cwd=api.vars.skia_dir, env=api.infra.go_env): 51 bookmaker_binary = api.path.join(api.vars.skia_out, api.vars.configuration, 52 'bookmaker') 53 buildername = api.vars.builder_name 54 55 if 'PerCommit' in buildername: 56 # Check to see if docs matches include/core. 57 cmd = [bookmaker_binary, 58 '-a', 'docs/status.json', # File containing status of docs. 59 '-x', # Check bmh against includes. 60 ] 61 try: 62 api.run(api.step, 'Validate docs match include/core/*.h', cmd=cmd) 63 except api.step.StepFailure as e: 64 # Display what needs to be fixed. 65 e.reason += ( 66 '\n\nView the output of the "Validate docs match include/core/*.h" ' 67 'step to see how to get this bot green.' 68 '\n\nhttps://skia.org/user/api/usingBookmaker details how to build ' 69 'and run the bookmaker utility locally if needed.') 70 raise e 71 72 elif 'Nightly' in buildername: 73 fiddlecli_binary = api.path.join(api.infra.gopath, 'bin', 'fiddlecli') 74 fiddlecli_input = api.path.join(api.path['start_dir'], 'fiddle.json') 75 fiddlecli_output = api.path.join(api.path['start_dir'], 'fiddleout.json') 76 77 # Step 1: Extract all fiddles out of markdown files. 78 cmd = [bookmaker_binary, 79 '-a', 'docs/status.json', # File containing status of docs. 80 '-e', fiddlecli_input, # Fiddle cli input. 81 ] 82 api.run(api.step, 'Extract all fiddles out of md files', cmd=cmd) 83 84 # Step 2: Forces fiddle.skia.org to compile all fiddles extracted out of 85 # markdown files and get output in JSON. 86 cmd = [fiddlecli_binary, 87 '--input', fiddlecli_input, 88 '--output', fiddlecli_output, 89 '--logtostderr', 90 '--force', 91 ] 92 api.run(api.step, 'Force fiddle to compile all examples', cmd=cmd) 93 94 # Step 3: Scan the output of fiddlecli for any compiletime/runtime errors. 95 # Fail the recipe is there are any errors and summarize results at 96 # the end. 97 if api.path.exists(fiddlecli_output): 98 test_data = api.properties.get('fiddleout_test_data', '{}') 99 content = api.file.read_text('Read fiddleout.json', 100 fiddlecli_output, test_data=test_data) 101 out = json.loads(content) 102 # Do a dump of fiddlecli_output. Will be useful for debugging. 103 print 'Dump of %s:' % fiddlecli_output 104 print json.dumps(out, indent=4) 105 106 failing_fiddles_to_errors = {} 107 for fiddle_name in out: 108 props = out[fiddle_name] 109 if props['compile_errors'] or props['runtime_error']: 110 # Construct the error. 111 error = props['runtime_error'] 112 if props['compile_errors']: 113 for e in props['compile_errors']: 114 error += '%s\n' % e['text'] 115 failing_fiddles_to_errors[props['fiddleHash']] = error 116 117 if failing_fiddles_to_errors: 118 # create an eror message and fail the bot! 119 failure_msg = 'Failed fiddles with their errors:\n\n\n' 120 counter = 0 121 for fiddle_hash, error in failing_fiddles_to_errors.iteritems(): 122 counter += 1 123 failure_msg += '%d. https://fiddle.skia.org/c/%s\n\n' % ( 124 counter, fiddle_hash) 125 failure_msg += '%s\n\n' % error 126 raise api.step.StepFailure(failure_msg) 127 128 # Step 4: Update docs in site/user/api/ with the output of fiddlecli. 129 # If there are any new changes then upload and commit the changes. 130 update_docs_gitcookies = api.path['start_dir'].join( 131 UPDATE_DOCS_GITCOOKIES_FILE) 132 cmd = ['python', 133 api.vars.skia_dir.join('infra', 'bots', 'upload_md.py'), 134 '--bookmaker_binary', bookmaker_binary, 135 '--fiddlecli_output', fiddlecli_output, 136 '--gitcookies', str(update_docs_gitcookies)] 137 with api.infra.DownloadGitCookies( 138 UPDATE_DOCS_GITCOOKIES_GS_PATH, update_docs_gitcookies, api): 139 with api.context(cwd=api.vars.skia_dir, env=api.infra.go_env): 140 api.run(api.step, 'Generate and Upload Markdown files', cmd=cmd) 141 142 143 def GenTests(api): 144 fiddleout_no_errors_test_data = """ 145 {"fiddle1": {"fiddleHash": "abc", 146 "compile_errors": [], 147 "runtime_error": ""}} 148 """ 149 fiddleout_with_errors_test_data = """ 150 {"fiddle1": {"fiddleHash": "abc", 151 "compile_errors": [ 152 { 153 "text": "ninja: Entering directory `out/Release'", 154 "line": 0, 155 "col": 0 156 }, 157 { 158 "text": "[1/7] ACTION //:skia.h(//gn/toolchain:gcc_like)", 159 "line": 0, 160 "col": 0 161 }, 162 { 163 "text": "[2/7] stamp obj/skia.h.stamp", 164 "line": 0, 165 "col": 0 166 }, 167 { 168 "text": "[3/7] compile ../../tools/fiddle/draw.cpp", 169 "line": 0, 170 "col": 0 171 }, 172 { 173 "text": "FAILED: obj/tools/fiddle/fiddle.draw.o ", 174 "line": 0, 175 "col": 0 176 }, 177 { 178 "text": "c++ -MMD -MF obj/tools/fiddle/fiddle.draw.o.d -DNDEBUG -DSK_HAS_HEIF_LIBRARY -DSK_HAS_JPEG_LIBRARY -DSK_SUPPORT_PDF -DSK_PDF_USE_SFNTLY -DSK_HAS_PNG_LIBRARY -DSK_CODEC_DECODES_RAW -DSK_HAS_WEBP_LIBRARY -DSK_XML -DSK_GAMMA_APPLY_TO_A8 -DSK_ENABLE_DISCRETE_GPU -DGR_TEST_UTILS=1 -DSK_SAMPLES_FOR_X -DSK_SUPPORT_ATLAS_TEXT=1 -I../../tools/flags -I../../include/private -I../../src/c -I../../src/codec -I../../src/core -I../../src/effects -I../../src/fonts -I../../src/image -I../../src/images -I../../src/lazy -I../../src/opts -I../../src/pathops -I../../src/pdf -I../../src/ports -I../../src/sfnt -I../../src/shaders -I../../src/shaders/gradients -I../../src/sksl -I../../src/utils -I../../src/utils/win -I../../src/xml -I../../third_party/gif -I../../src/gpu -I../../tools/gpu -I../../include/android -I../../include/c -I../../include/codec -I../../include/config -I../../include/core -I../../include/effects -I../../include/encode -I../../include/gpu -I../../include/gpu/gl -I../../include/atlastext -I../../include/pathops -I../../include/ports -I../../include/svg -I../../include/utils -I../../include/utils/mac -I../../include/atlastext -Igen -fstrict-aliasing -fPIC -Werror -Wall -Wextra -Winit-self -Wpointer-arith -Wsign-compare -Wvla -Wno-deprecated-declarations -Wno-maybe-uninitialized -Wno-unused-parameter -O3 -fdata-sections -ffunction-sections -g -std=c++11 -fno-exceptions -fno-rtti -Wnon-virtual-dtor -Wno-error -c ../../tools/fiddle/draw.cpp -o obj/tools/fiddle/fiddle.draw.o", 179 "line": 0, 180 "col": 0 181 }, 182 { 183 "text": "../../tools/fiddle/draw.cpp: In function 'void draw(SkCanvas*)':", 184 "line": 0, 185 "col": 0 186 }, 187 { 188 "text": "draw.cpp:5:12: error: aggregate 'SkMask mask' has incomplete type and cannot be defined", 189 "line": 5, 190 "col": 12 191 }, 192 { 193 "text": " }", 194 "line": 0, 195 "col": 0 196 }, 197 { 198 "text": " ^ ", 199 "line": 0, 200 "col": 0 201 }, 202 { 203 "text": "draw.cpp:6:28: error: incomplete type 'SkMask' used in nested name specifier", 204 "line": 6, 205 "col": 28 206 }, 207 { 208 "text": " ", 209 "line": 0, 210 "col": 0 211 }, 212 { 213 "text": " ^ ", 214 "line": 0, 215 "col": 0 216 }, 217 { 218 "text": "draw.cpp:14:28: error: incomplete type 'SkMask' used in nested name specifier", 219 "line": 14, 220 "col": 28 221 }, 222 { 223 "text": " uint8_t bytes[] = { 0, 1, 2, 3, 4, 5, 6, 7 };", 224 "line": 0, 225 "col": 0 226 }, 227 { 228 "text": " ^~~~~~~~~~", 229 "line": 0, 230 "col": 0 231 }, 232 { 233 "text": "[4/7] compile ../../tools/fiddle/egl_context.cpp", 234 "line": 0, 235 "col": 0 236 }, 237 { 238 "text": "[5/7] compile ../../tools/fiddle/fiddle_main.cpp", 239 "line": 0, 240 "col": 0 241 }, 242 { 243 "text": "[6/7] link libskia.a", 244 "line": 0, 245 "col": 0 246 }, 247 { 248 "text": "ninja: build stopped: subcommand failed.", 249 "line": 0, 250 "col": 0 251 }, 252 { 253 "text": "", 254 "line": 0, 255 "col": 0 256 } 257 ], 258 "runtime_error": ""}} 259 """ 260 yield ( 261 api.test('percommit_bookmaker') + 262 api.properties(buildername='Housekeeper-PerCommit-Bookmaker', 263 repository='https://skia.googlesource.com/skia.git', 264 revision='abc123', 265 path_config='kitchen', 266 swarm_out_dir='[SWARM_OUT_DIR]') 267 ) 268 269 yield ( 270 api.test('percommit_failed_validation') + 271 api.properties(buildername='Housekeeper-PerCommit-Bookmaker', 272 repository='https://skia.googlesource.com/skia.git', 273 revision='abc123', 274 path_config='kitchen', 275 swarm_out_dir='[SWARM_OUT_DIR]') + 276 api.step_data('Validate docs match include/core/*.h', retcode=1) 277 ) 278 279 yield ( 280 api.test('nightly_bookmaker') + 281 api.properties(buildername='Housekeeper-Nightly-Bookmaker', 282 repository='https://skia.googlesource.com/skia.git', 283 revision='abc123', 284 path_config='kitchen', 285 fiddleout_test_data=fiddleout_no_errors_test_data, 286 swarm_out_dir='[SWARM_OUT_DIR]') + 287 api.path.exists(api.path['start_dir'].join('fiddleout.json'), 288 api.path['start_dir'].join(UPDATE_DOCS_GITCOOKIES_FILE)) 289 ) 290 291 yield ( 292 api.test('nightly_failed_fiddles') + 293 api.properties(buildername='Housekeeper-Nightly-Bookmaker', 294 repository='https://skia.googlesource.com/skia.git', 295 revision='abc123', 296 path_config='kitchen', 297 fiddleout_test_data=fiddleout_with_errors_test_data, 298 swarm_out_dir='[SWARM_OUT_DIR]') + 299 api.path.exists(api.path['start_dir'].join('fiddleout.json')) 300 ) 301 302 yield ( 303 api.test('nightly_failed_extract_fiddles') + 304 api.properties(buildername='Housekeeper-Nightly-Bookmaker', 305 repository='https://skia.googlesource.com/skia.git', 306 revision='abc123', 307 path_config='kitchen', 308 swarm_out_dir='[SWARM_OUT_DIR]') + 309 api.step_data('Extract all fiddles out of md files', retcode=1) 310 ) 311 312 yield ( 313 api.test('nightly_failed_fiddlecli') + 314 api.properties(buildername='Housekeeper-Nightly-Bookmaker', 315 repository='https://skia.googlesource.com/skia.git', 316 revision='abc123', 317 path_config='kitchen', 318 swarm_out_dir='[SWARM_OUT_DIR]') + 319 api.step_data('Force fiddle to compile all examples', retcode=1) 320 ) 321 322 yield ( 323 api.test('nightly_failed_upload') + 324 api.properties(buildername='Housekeeper-Nightly-Bookmaker', 325 repository='https://skia.googlesource.com/skia.git', 326 revision='abc123', 327 path_config='kitchen', 328 swarm_out_dir='[SWARM_OUT_DIR]') + 329 api.step_data('Generate and Upload Markdown files', retcode=1) 330 ) 331