marcells/node-build-monitor

View on GitHub
app/services/Jenkins.js

Summary

Maintainability
F
3 days
Test Coverage
var request = require('request'),
    async = require('async'),
    makeRequestConfiguration = function (serviceConfiguration) {
        var tryApplyAuthHeader = function (requestConfig, key, value) {
            if (!value) return;

            requestConfig.auth = requestConfig.auth || {};
            requestConfig.auth[key] = value;
        };

        var requestConfig = serviceConfiguration.options || {};

        tryApplyAuthHeader(requestConfig, 'user', serviceConfiguration.username);
        tryApplyAuthHeader(requestConfig, 'pass', serviceConfiguration.password);

        return requestConfig;
    },
    makeRequest = function (requestWithDefaults, url, callback) {
        requestWithDefaults({
            'url': url,
            'headers': { 'Accept': 'application/json' }
        },
            function (error, response, body) {
                if (error || response.statusCode !== 200) {
                    callback(error || true);
                    return;
                }

                try {
                    var json = JSON.parse(body);
                    callback(error, json);
                } catch (e) {
                    callback(e);
                }
            });
    };

module.exports = function () {
    var self = this,
        requestWithDefaults,
        flatten = function (arrayOfArray) {
            return [].concat.apply([], arrayOfArray);
        },
        requestBuildsForJob = function (job, jobUrl, callback) {
            if (jobUrl == '') {
                jobUrl = self.configuration.url + '/job/' + job;
            }
            requestBuildsForJobByUrl(job, jobUrl, callback);
        },
        requestBuildsForJobByUrl = function (job, url, callback) {
            if (url.substr(url.length - 1, 1) !== '/') {
                url = url + '/';
            }
            makeRequest(requestWithDefaults, url + 'api/json', function (error, data) {
                if (error) {
                    callback(error);
                    return;
                }

                if (typeof self.configuration.numberOfBuildsPerJob !== 'undefined') {
                    data.builds = data.builds.slice(0, self.configuration.numberOfBuildsPerJob);
                }

                data.builds.forEach(function (build) {
                    build.jobId = job;
                });

                callback(error, data.builds);
            });
        },
        requestBuild = function (build, callback) {
            makeRequest(requestWithDefaults, build.url + 'api/json', function (error, data) {
                if (error) {
                    callback(error);
                    return;
                }

                data.jobId = build.jobId;

                callback(error, simplifyBuild(data));
            });
        },
        requestJobsForView = function (viewId, callback) {
            makeRequest(requestWithDefaults, self.configuration.url + '/view/' + viewId + '/api/json', function (error, data) {
                if (error) {
                    callback(error);
                    return;
                }

                callback(error, data.jobs);
            });
        },
        queryBuildsForJob = function (jobId, jobUrl, callback) {
            requestBuildsForJob(jobId, jobUrl, function (error, body) {
                if (error) {
                    callback(error);
                    return;
                }

                async.map(body, requestBuild, function (error, results) {
                    callback(error, results);
                });
            });
        },
        queryBuildsForView = function (viewId, callback) {
            requestJobsForView(viewId, function (error, body) {
                if (error) {
                    callback(error);
                    return;
                }

                async.map(body, function (job, callback) {
                    queryBuildsForJob(job.name, job.url, callback);
                }, function (error, results) {
                    callback(error, flatten(results));
                });
            });
        },
        parseDate = function (dateAsString) {
            return new Date(dateAsString);
        },
        getStatus = function (build) {
            if (build.building) return "Blue";
            var result = build.result;
            if (result === 'FAILURE') return "Red";
            if (result === 'SUCCESS') return "Green";
            if (result === 'UNSTABLE') return "#ffa500";
            if (result === 'NOT_BUILT') return "Blue";
            if (result === 'ABORTED') return "Gray";
            if (result === null) return "Blue";

            return null;
        },
        getStatusText = function (build) {
            if (build.building) return "Running";
            var result = build.result;
            if (result === 'FAILURE') return "Failure";
            if (result === 'SUCCESS') return "Success";
            if (result === 'UNSTABLE') return "Unstable";
            if (result === 'NOT_BUILT') return "Running";
            if (result === 'ABORTED') return "Aborted";
            if (result === null) return "Running";

            return null;
        },
        getRequestedFor = function (build) {
            if (build.actions) {
                for (var i = 0; i < build.actions.length; i++) {
                    var action = build.actions[i];
                    if ((action) && (action.causes)) {
                        for (var j = 0; j < action.causes.length; j++) {
                            var cause = action.causes[j];
                            if (cause && cause.userName) {
                                return cause.userName;
                            }
                        }
                    }
                }
            }

            return "Unknown";
        },
        simplifyBuild = function (res) {
            return {
                id: res.jobId + '|' + res.id,
                project: res.jobId,
                number: res.number,
                isRunning: res.building,
                startedAt: parseDate(res.timestamp),
                finishedAt: parseDate(res.timestamp + res.duration),
                requestedFor: getRequestedFor(res),
                status: getStatus(res),
                statusText: getStatusText(res),
                reason: "Build",
                hasErrors: false,
                hasWarnings: res.result == 'UNSTABLE',
                url: res.url
            };
        };

    self.configure = function (config) {
        self.configuration = config;

        if (self.configuration.url.indexOf('@') > -1) {
            throw new Error(
                'Breaking Configuration change:\n' +
                'To display build details, the url parameter is now published to the client. \n' +
                'This leads to a security risk, cause your credentials would also be published. \n' +
                'Please use now the \'username\' and \'password\' options. \n' +
                'More information on: https://github.com/marcells/node-build-monitor#jenkins \n\n');
        }

        requestWithDefaults = request.defaults(makeRequestConfiguration(self.configuration));
    };

    self.check = function (callback) {
        if (self.configuration.view) {
            queryBuildsForView(self.configuration.view, callback);
        } else {
            queryBuildsForJob(self.configuration.job, '', callback);
        }
    };
};