@@ -236,7 +236,11 @@ func build(buildCtx *BuildContext) error {
236236 }
237237 }
238238
239- // build builders (TODO: check cache so this is not done unless necessary?)
239+ // build builders.
240+ //
241+ // it would be cool to not invoke Docker if this is cached anyway, but the analysis would have
242+ // to include modification check for the Dockerfile and all of its build context, so we're just
243+ // best off calling Docker build because it is the best at detecting cache invalidation.
240244 for _ , builder := range buildCtx .Bobfile .Builders {
241245 builder := builder // pin
242246
@@ -259,38 +263,40 @@ func build(buildCtx *BuildContext) error {
259263 }
260264 }
261265
262- // two passes:
263- // 1) run all builds with all phases except publish
264- // 2) run all builds with only publish phase (but only if publish requested)
266+ // three-pass process. the flow is well documented in *BuilderCommands* type
267+ pass := func (opDesc string , getCommand func (cmds BuilderCommands ) []string ) error {
268+ for _ , builder := range buildCtx .Bobfile .Builders {
269+ if buildCtx .BuilderNameFilter != "" && builder .Name != buildCtx .BuilderNameFilter {
270+ continue
271+ }
265272
266- // 1)
267- for _ , builder := range buildCtx .Bobfile .Builders {
268- if buildCtx .BuilderNameFilter != "" && builder .Name != buildCtx .BuilderNameFilter {
269- continue
270- }
273+ cmd := getCommand (builder .Commands )
274+ if len (cmd ) == 0 { // no command for this step specified
275+ continue
276+ }
271277
272- if len (builder .Commands .Build ) == 0 {
273- continue
278+ if err := runBuilder (builder , buildCtx , opDesc , cmd ); err != nil {
279+ return fmt .Errorf ("%s.%s: %w" , builder .Name , opDesc , err )
280+ }
274281 }
275282
276- if err := runBuilder (builder , buildCtx , "build" , builder .Commands .Build ); err != nil {
277- return err
278- }
283+ return nil
279284 }
280285
281- // 2)
282- for _ , builder := range buildCtx .Bobfile .Builders {
283- if buildCtx .BuilderNameFilter != "" && builder .Name != buildCtx .BuilderNameFilter {
284- continue
285- }
286+ preparePass := func (cmds BuilderCommands ) []string { return cmds .Prepare }
287+ buildPass := func (cmds BuilderCommands ) []string { return cmds .Build }
288+ publishPass := func (cmds BuilderCommands ) []string { return cmds .Publish }
286289
287- if ! buildCtx . PublishArtefacts || len ( builder . Commands . Publish ) == 0 {
288- continue
289- }
290+ if err := pass ( "prepare" , preparePass ); err != nil {
291+ return err // err context ok
292+ }
290293
291- if err := runBuilder (builder , buildCtx , "publish" , builder .Commands .Publish ); err != nil {
292- return err
293- }
294+ if err := pass ("build" , buildPass ); err != nil {
295+ return err // err context ok
296+ }
297+
298+ if err := pass ("publish" , publishPass ); err != nil {
299+ return err // err context ok
294300 }
295301
296302 dockerLoginCache := newDockerRegistryLoginCache ()
0 commit comments