0

I am fairly new to the world of Javascript promises and am having issues implementing the following:

var Promise = require('bluebird');
var jenkinsapi = require('jenkins-api');
var asyncJenkinsAPI = Promise.promisifyAll(jenkinsapi);
var jenkins = asyncJenkinsAPI.init("http://<user>:<password>@localhost:8080");

app.get('/api/servers', function(req, resp) {
    SavedJob.find({})
        .then(function(jobs) {
            return Promise.all(jobs.map(function(job){
                // do two calls with each job.name
                // build new data with the result of the two calls
                // return new data to next part of chain
                var job_status = jenkins.job_info(job.name, function(err, jobData) { return jobData; });
                var build_info = jenkins.last_build_info(job.name, function(err, buildData) { return buildData; });
                return {task_name: job_status.name,
                        status: STATUSMAP[job_status.color] || "UNKNOWN",
                        latest_build:
                            {
                                build_date: build_info.timestamp,
                                build_status: build_info.result,
                                build_number: build_info.number,
                                build_url: build_info.url
                            }
                        };
            }));
        })
        .then(function(results){
            console.log(results);
        });
    });

How can I best implement making two asynchronous calls inside the Promise.all() with each job.name and have the set of results at the end?

Muttonchop
  • 353
  • 4
  • 22

1 Answers1

1

After having promisified jenkins, you will need to use the new promise-returning methods:

var job_promise = jenkins.job_infoAsync(job.name);
var build_promise = jenkins.last_build_infoAsync(job.name);

(you might want to pass {suffix: "_async"} as an option to promisifyAll for nicer method names).

Then combine those two promises (Promise.all/Promise.props/Promise.join):

return Promise.join(job_promise, build_promise, function(job_status, build_info) {
    return {
        task_name: job_status.name,
        status: STATUSMAP[job_status.color] || "UNKNOWN",
        latest_build: {
            build_date: build_info.timestamp,
            build_status: build_info.result,
            build_number: build_info.number,
            build_url: build_info.url
        }
    };
});

The rest of your code (mapping, chaining) is working fine.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • After putting your solution into the code, I am getting that `name` is undefined. Also, using `Async` (and trying putting in `_async` into promisify) suffix returns an error saying they are not functions. – Muttonchop Aug 18 '16 at 17:02
  • Which name is undefined? The property? Is that an error? – Bergi Aug 18 '16 at 17:06
  • Yes, if you pass the suffix you'd have to use `.job_info_async(…)` and `.last_build_info_async(…)` of course instead of the default `Async` suffix – Bergi Aug 18 '16 at 17:07
  • `var asyncJenkinsAPI = Promise.promisifyAll(jenkinsapi);` and using `.job_infoAsync(…)` throws an TypeError saying it is not a function. – Muttonchop Aug 18 '16 at 17:11
  • That's weird, it should work. Maybe try `asyncJenkinsAPI.job_…`, otherwise open a bug with Bluebird. – Bergi Aug 18 '16 at 17:19
  • Regarding `job_status`, it doesn't throw an error about `name` being undefined, rather about accessing a `.name` property on `undefined`. I messed up the paramter name. But still, this is very weird, code evaluation should not even get till there if `job_infoAsync(…)` already threw. – Bergi Aug 18 '16 at 17:22
  • The solution to this ended up `promisify`-ing the individual call in the jenkins api. – Muttonchop Aug 18 '16 at 18:55
  • @Muttonchop Glad you found a solution :-) If my answer was helpful, please accept it. And file a bug with Bluebird that `promisifyAll` doesn't work for `jenkins-api`. – Bergi Aug 18 '16 at 19:15