Slide 1

Slide 1 text

Recipes Python-based DSL for specifying build/test instructions in Chromium/V8

Slide 2

Slide 2 text

Overview ● Buildbot ● Recipes ○ How they work? ○ Examples & Features ● Current State ● Q&A

Slide 3

Slide 3 text

Buildbot ● “It runs the waterfalls” ● All-in-one opinionated CI framework ○ Promises to be ‘batteries included’, and yet ‘flexible’ ○ Spoiler: it lies

Slide 4

Slide 4 text

Buildbot

Slide 5

Slide 5 text

Buildbot What is it good for? ● Simple build dependencies ● Linear build execution ● Small number of build configurations As it turns out, this doesn’t fit the Chromium/V8 projects these days.

Slide 6

Slide 6 text

Buildbot

Slide 7

Slide 7 text

this is the problem Buildbot

Slide 8

Slide 8 text

● Centralized configuration ○ Static builder configurations ○ Unversionable on a per-build basis ■ Not tryable ○ Requires master restart to change ● Iron-fisted RPC control of the slave ○ Restarting master kills all running jobs. ● Callback-passing style (twistd) ○ Difficult to debug ○ Difficult to test Problems?

Slide 9

Slide 9 text

How do we move control of the builders from the master to the slave?

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

How Recipes Work ● Master triggers a single command on the slave ○ recipes.py --recipe chromium.py ● The recipe executes and generates commands to build/test your project ○ git clone ○ python compile.py ○ ... ● Recipe framework executes them and sends logs back to master ● Master will parse the logs and extract annotations to generate steps ○ @@@SEED_STEP@setup_build@@@ ○ @@@STEP_STARTED@@@

Slide 12

Slide 12 text

DEPS = ['chromium', 'gclient', 'properties', 'platform'] def RunSteps(api): # 100% working example! api.gclient.set_config('chromium') api.gclient.checkout(revision=api.properties[ 'revision']) api.gclient.runhooks() api.chromium.cleanup_temp() api.chromium.compile(targets=['all']) def GenTests(api): yield api.test('basic') yield api.test('tryserver') + api.properties.tryserver() yield api.test('mac_32') + api.platform('mac', 32) Simple Recipe

Slide 13

Slide 13 text

gclient config --spec ... gclient sync gclient runhooks cleanup_temp python compile.py --targets all Simple Recipe

Slide 14

Slide 14 text

DEPS = ['chromium', 'gclient', 'tryserver'] def compile_and_test(api): api.gclient.runhooks() api.chromium.compile() return api.chromium.runtest('v8/test262').json.failed_tests def RunSteps(api): api.gclient.set_config('chromium_with_v8_tot') api.gclient.checkout() api.tryserver.apply_patch() failed_tests_with_patch = compile_and_test() if not failed_tests_with_patch: return # patch is OK api.tryserver.deapply_patch() failed_tests_without_patch = compile_and_test() # patch is OK iff failed_tests_with_patch == failed_tests_without_patch Try a Test With and Without a Patch

Slide 15

Slide 15 text

--- a/scripts/slave/recipes/chromium.py +++ b/scripts/slave/recipes/chromium.py @@ -122,7 +122,7 @@ BUILDERS = { 'recipe_config': 'official', 'chromium_config_kwargs': { 'BUILD_CONFIG': 'Release', 'TARGET_BITS': 64,32, }, 'testing': { 'platform': 'win', Automatic Simulation / Tests

Slide 16

Slide 16 text

--- a/.../chromium_chrome_Google_Chrome_Win.json +++ b/.../chromium_chrome_Google_Chrome_Win.json @@ -71,8 +71,8 @@ "runhooks" ], "env": { "GYP_DEFINES": "branding=Chrome buildtype=Official chromium_win_pch=0 component=static_library fastbuild=1 target_arch=x64",target_arch=ia32", "GYP_MSVS_VERSION": "2012""2010" }, "name": "gclient runhooks" }, Automatic Simulation / Tests --- a/.../chromium_chrome_Google_Chrome_Win.json +++ b/.../chromium_chrome_Google_Chrome_Win.json @@ -91,7 +91,7 @@ "-u", "[BUILD]\\scripts\\slave\\compile.py", "--target", "Release_x64","Release", "--src-dir", "[SLAVE_BUILD]\\src", "--build-tool",

Slide 17

Slide 17 text

Mocking Command Outputs & Unit Tests DEPS = ['gpu', 'gclient', 'properties', 'platform'] def GenTests(api): yield ( api.test('failed_gpu_test_keeps_build_green' ) + api.override_step_data( 'gpu_process_launch_tests on NVIDIA GPU on Windows' , api.gpu.example_test_failure( 'GpuProcessIntegrationTest.GpuProcess_css3d' ), retcode=1) + api.post_process(post_process .StatusCodeIn, 0) + api.post_process(post_process .DropExpectation) )

Slide 18

Slide 18 text

Back in 2014

Slide 19

Slide 19 text

Today ● We’ve replaced Buildbot with LUCI ○ A set of micro-services that work in Cloud to provide a scalable CI system. ● Most services are implemented in Go ● Yet, all build/test logic is still implemented as recipes! ○ And works seamlessly with a completely different underlying architecture. ● Mature and reliable system ○ Tested on dozens of projects ○ Users wrote hundreds of recipes It’s fully open source! Try it out for your projects.

Slide 20

Slide 20 text

Thank You https://github.com/luci/recipes-py