1313import subprocess
1414from pathlib import Path
1515
16- DEFAULT_INSTANCES = [
17- "c5n.metal" , # Intel Skylake
18- "m5n.metal" , # Intel Cascade Lake
19- "m6i.metal" , # Intel Icelake
20- "m6a.metal" , # AMD Milan
21- "m6g.metal" , # Graviton2
22- "m7g.metal" , # Graviton3
23- ]
16+ DEFAULT_INSTANCES = {
17+ "c5n.metal" : "x86_64" , # Intel Skylake
18+ "m5n.metal" : "x86_64" , # Intel Cascade Lake
19+ "m6i.metal" : "x86_64" , # Intel Icelake
20+ "m6a.metal" : "x86_64" , # AMD Milan
21+ "m6g.metal" : "aarch64" , # Graviton2
22+ "m7g.metal" : "aarch64" , # Graviton3
23+ }
2424
2525DEFAULT_PLATFORMS = [
2626 ("al2" , "linux_5.10" ),
@@ -145,7 +145,7 @@ def __call__(self, parser, namespace, value, option_string=None):
145145 "--instances" ,
146146 required = False ,
147147 nargs = "+" ,
148- default = DEFAULT_INSTANCES ,
148+ default = DEFAULT_INSTANCES . keys () ,
149149)
150150COMMON_PARSER .add_argument (
151151 "--platforms" ,
@@ -188,6 +188,7 @@ def ab_revision_build(revision):
188188 "git branch $$branch_name $$commitish" ,
189189 f"git clone -b $$branch_name . build/{ revision } " ,
190190 f"cd build/{ revision } && ./tools/devtool -y build --release && cd -" ,
191+ "git branch -D $$branch_name" ,
191192 ]
192193
193194
@@ -204,7 +205,9 @@ def shared_build():
204205 if rev_a is not None :
205206 rev_b = os .environ .get ("REVISION_B" )
206207 assert rev_b is not None , "REVISION_B environment variable not set"
207- build_cmds = ab_revision_build (rev_a ) + ab_revision_build (rev_b )
208+ build_cmds = ab_revision_build (rev_a )
209+ if rev_a != rev_b :
210+ build_cmds += ab_revision_build (rev_b )
208211 elif os .environ .get ("BUILDKITE_PULL_REQUEST" , "false" ) != "false" :
209212 build_cmds = ab_revision_build (
210213 os .environ .get ("BUILDKITE_PULL_REQUEST_BASE_BRANCH" , "main" )
@@ -229,7 +232,7 @@ class BKPipeline:
229232
230233 parser = COMMON_PARSER
231234
232- def __init__ (self , initial_steps = None , ** kwargs ):
235+ def __init__ (self , with_build_step = True , ** kwargs ):
233236 self .steps = []
234237 self .args = args = self .parser .parse_args ()
235238 # Retry one time if agent was lost. This can happen if we terminate the
@@ -252,42 +255,36 @@ def __init__(self, initial_steps=None, **kwargs):
252255 self .per_arch ["platforms" ] = [("al2" , "linux_5.10" )]
253256 self .binary_dir = args .binary_dir
254257 # Build sharing
255- build_cmds , self .shared_build = shared_build ()
256- step_build = group ("🏗️ Build" , build_cmds , ** self .per_arch )
257- self .steps += [step_build , "wait" ]
258-
259- # If we run initial_steps before the "wait" step above, then a failure of the initial steps
260- # would result in the build not progressing past the "wait" step (as buildkite only proceeds past a wait step
261- # if everything before it passed). Thus put the initial steps after the "wait" step, but set `"depends_on": null`
262- # to start running them immediately (e.g. without waiting for the "wait" step to unblock).
263- #
264- # See also https://buildkite.com/docs/pipelines/dependencies#explicit-dependencies-in-uploaded-steps
265- if initial_steps :
266- for step in initial_steps :
267- step ["depends_on" ] = None
268-
269- self .steps += initial_steps
270-
271- def add_step (self , step , decorate = True ):
258+ if with_build_step :
259+ build_cmds , self .shared_build = shared_build ()
260+ self .build_group_per_arch (
261+ "🏗️ Build" , build_cmds , depends_on_build = False , set_key = True
262+ )
263+ else :
264+ self .shared_build = None
265+
266+ def add_step (self , step , depends_on_build = True ):
272267 """
273268 Add a step to the pipeline.
274269
275270 https://buildkite.com/docs/pipelines/step-reference
276271
277272 :param step: a Buildkite step
278- :param decorate : inject needed commands for sharing builds
273+ :param depends_on_build : inject needed commands for sharing builds
279274 """
280- if decorate and isinstance (step , dict ):
275+ if depends_on_build and isinstance (step , dict ):
281276 step = self ._adapt_group (step )
282277 self .steps .append (step )
283278 return step
284279
285280 def _adapt_group (self , group ):
286281 """"""
287- prepend = [
288- f'buildkite-agent artifact download "{ self .shared_build } " .' ,
289- f"tar xzf { self .shared_build } " ,
290- ]
282+ prepend = []
283+ if self .shared_build is not None :
284+ prepend = [
285+ f'buildkite-agent artifact download "{ self .shared_build } " .' ,
286+ f"tar xzf { self .shared_build } " ,
287+ ]
291288 if self .binary_dir is not None :
292289 prepend .extend (
293290 [
@@ -298,6 +295,10 @@ def _adapt_group(self, group):
298295
299296 for step in group ["steps" ]:
300297 step ["command" ] = prepend + step ["command" ]
298+ if self .shared_build is not None :
299+ step ["depends_on" ] = self .build_key (
300+ DEFAULT_INSTANCES [step ["agents" ]["instance" ]]
301+ )
301302 return group
302303
303304 def build_group (self , * args , ** kwargs ):
@@ -306,15 +307,34 @@ def build_group(self, *args, **kwargs):
306307
307308 https://buildkite.com/docs/pipelines/group-step
308309 """
310+ depends_on_build = kwargs .pop ("depends_on_build" , True )
309311 combined = overlay_dict (self .per_instance , kwargs )
310- return self .add_step (group (* args , ** combined ))
312+ return self .add_step (
313+ group (* args , ** combined ), depends_on_build = depends_on_build
314+ )
315+
316+ def build_key (self , arch ):
317+ """Return the Buildkite key for the build step, for the specified arch"""
318+ return self .shared_build .replace ("$(uname -m)" , arch ).replace (".tar.gz" , "" )
311319
312- def build_group_per_arch (self , * args , ** kwargs ):
320+ def build_group_per_arch (self , label , * args , ** kwargs ):
313321 """
314322 Build a group, parametrizing over the architectures only.
323+
324+ kwargs consumed by this method and not passed down to `group`:
325+ - `depends_on_build` (default: `True`): Whether the steps in this group depend on the artifacts from the shared compilation steps
326+ - `set_key`: If True, causes the generated steps to have a "key" field
315327 """
328+ depends_on_build = kwargs .pop ("depends_on_build" , True )
329+ set_key = kwargs .pop ("set_key" , None )
316330 combined = overlay_dict (self .per_arch , kwargs )
317- return self .add_step (group (* args , ** combined ))
331+ grp = group (label , * args , ** combined )
332+ if set_key :
333+ for step in grp ["steps" ]:
334+ step ["key" ] = self .build_key (
335+ DEFAULT_INSTANCES [step ["agents" ]["instance" ]]
336+ )
337+ return self .add_step (grp , depends_on_build = depends_on_build )
318338
319339 def to_dict (self ):
320340 """Render the pipeline as a dictionary."""
@@ -327,7 +347,9 @@ def to_json(self):
327347 def devtool_test (self , devtool_opts = None , pytest_opts = None ):
328348 """Generate a `devtool test` command"""
329349 cmds = []
330- parts = ["./tools/devtool -y test" , "--no-build" ]
350+ parts = ["./tools/devtool -y test" ]
351+ if self .shared_build is not None :
352+ parts .append ("--no-build" )
331353 if devtool_opts :
332354 parts .append (devtool_opts )
333355 parts .append ("--" )
0 commit comments