docs: function (user, config, job, dirs, done) {
      var self = this;
      var tasks = [function (next) {
        var plugin = self.extensions.provider[job.project.provider.id];
        if (!plugin) {
          var msg = `Provider plugin '${job.project.provider.id}' not found in this environment!`;
          return next(new Error(msg));
        }
        var finished = t(function (err, provider) {
          if (provider) provider.id = job.project.provider.id;
          next(err, provider);
        });
        if (!plugin.hosted) {
          return plugin.init(dirs, job.providerConfig, job, finished);
        }
        plugin.init(dirs, user.account(job.project.provider).config, job.providerConfig, job, finished);
      }];
      // XXX: do we want/need more things in the context? See
      // extension-loader readme for what gets passed in to the
      // individual phase functions as "Phase context"
      var context = {
        baseDir: dirs.base,
        dataDir: dirs.data,
        cacheDir: dirs.cache
      };
      var anyPluginFailed = config.plugins.some(function (plugin) {
        if (false === plugin.enabled) {
          debug(`[runner:${self.id}] Found a disabled plugin: ${plugin.id} Project: ${job.project.name} Job ID: ${job._id}`);
          return;
        }
        if (!self.extensions.job[plugin.id]) {
          debug(`[runner:${self.id}] Error: Plugin not found ${plugin.id} Project: ${job.project.name} Job ID: ${job._id}`);
          debug('Plugin not found', plugin.id);
          done(new Error(`Plugin required but not found: ${plugin.id}`));
          return true;
        }
        debug(`Initializing plugin '${plugin.id}'...`);
        tasks.push(function (next) {
          var fn = self.extensions.job[plugin.id].init;
          var cb = t(function (err, obj) {
            if (obj) obj.id = plugin.id;
            next(err, obj);
          });
          switch (fn.length) {
          case 1:
            return fn(cb);
          case 2:
            return fn(plugin.config, cb);
          case 3:
            return fn(plugin.config, context, cb);
          case 4:
            return fn(plugin.config, job, context, cb);
          default:
            return fn(user.jobplugins && user.jobplugins[plugin.id], plugin.config, job, context, cb);
          }
        });
      });
      
      if (anyPluginFailed) return;
      
      async.parallel(tasks, function (err, results) {
        if (err) return done(err);
        done(null, {
          provider: results.shift(),
          jobplugins: results
        });
      });
    }