private Future<BuildResult> pushImage(
      Image baseImage,
      Future<Image> builtImage,
      ProgressEventDispatcher.Factory progressDispatcherFactory) {
    return executorService.submit(
        () -> {
          realizeFutures(
              Verify.verifyNotNull(results.baseImagesAndLayerPushResults.get().get(baseImage)));

          Future<BlobDescriptor> containerConfigPushResult =
              results.baseImagesAndContainerConfigPushResults.get().get(baseImage);

          List<Future<BuildResult>> manifestPushResults =
              scheduleCallables(
                  PushImageStep.makeList(
                      buildContext,
                      progressDispatcherFactory,
                      results.targetRegistryClient.get(),
                      Verify.verifyNotNull(containerConfigPushResult).get(),
                      builtImage.get(),
                      results.manifestCheckResult.get().isPresent()));

          realizeFutures(manifestPushResults);

          return manifestPushResults.isEmpty()
              ? new BuildResult(
                  results.manifestCheckResult.get().get().getDigest(),
                  Verify.verifyNotNull(containerConfigPushResult).get().getDigest(),
                  isImagePushed(results.manifestCheckResult.get()))
              // Manifest pushers return the same BuildResult.
              : manifestPushResults.get(0).get();
        });
  }
Run all steps and return a BuildResult after a build is completed.

@return a {@link BuildResult} with build metadata
@throws ExecutionException if an error occurred during asynchronous execution of steps
@throws InterruptedException if the build was interrupted while waiting for results
jib-core/src/main/java/com/google/cloud/tools/jib/builder/steps/StepsRunner.java