Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
  • 3 commits
  • 6 files changed
  • 0 commit comments
  • 1 contributor
Commits on May 23, 2012
@cliffano Move color to status conversion to a util module, adding animated and…
… non-color status handling.

This also fixes a bug where unknown color would display undefined status.
b949891
@cliffano Start refactoring process, replacing cli with bagofholding, comm#http…
… with request, and vows with mocha.
f1c4dd0
@cliffano Util is already moved to jenkins module. 45fed49
View
3  CHANGELOG.md
@@ -1,5 +1,6 @@
### 0.0.5 (SNAPSHOT)
-*
+* Another rewrite lib (bagofholding FTW)
+* Fix undefined job status display
### 0.0.4
* Display usage on arg-less comamand
View
2  README.md
@@ -1,7 +1,7 @@
Nestor [![http://travis-ci.org/cliffano/nestor](https://secure.travis-ci.org/cliffano/nestor.png?branch=master)](http://travis-ci.org/cliffano/nestor)
------
-Nestor is Node.js [Jenkins](http://jenkins-ci.org) command-line interface.
+[Jenkins](http://jenkins-ci.org) command-line interface in Node.js .
Installation
------------
View
84 lib/cli.js
@@ -1,3 +1,84 @@
+var bag = require('bagofholding'),
+ jenkins = require('./jenkins');
+
+/**
+ * cli#exec
+ *
+ * Execute jenkins
+ **/
+function exec() {
+
+ var url = process.env.JENKINS_URL || 'http://localhost:8080';
+
+ function _exec(command) {
+ return function () {
+ new jenkins(url)[command](bag.cli.exit);
+ };
+ }
+
+ function _build() {
+ var args = Array.prototype.slice.call(_build['arguments']),
+ jobs = args.slice(0, args.length - 1);
+
+ jobs.forEach(function (job) {
+ new jenkins(url).build(job);
+ });
+ }
+
+ function _dashboard() {
+ return function () {
+ new jenkins(url).dashboard(bag.cli.exitCb(null, function (result) {
+ if (result.length === 0) {
+ console.log('Jobless Jenkins');
+ } else {
+ result.forEach(function (job) {
+ console.log(job.status + ' - ' + job.name);
+ });
+ }
+ }));
+ };
+ }
+
+ function _job(job) {
+
+ }
+
+ var commands = {
+ build: {
+ desc: 'Trigger one or more builds',
+ action: _build
+ },
+ dashboard: {
+ desc: 'View status of all jobs',
+ action: _dashboard()
+ },
+ discover: {
+ desc: 'Discover Jenkins instance running on a specified host',
+ action: _exec('discover')
+ },
+ executor: {
+ desc: 'View executors\' activity (running builds)',
+ action: _exec('executor')
+ },
+ job: {
+ desc: 'View job status',
+ action: _job
+ },
+ queue: {
+ desc: 'View the build queue',
+ action: _exec('queue')
+ },
+ version: {
+ desc: 'View Jenkins version number',
+ action: _exec('version')
+ }
+ };
+
+ bag.cli.parse(commands, __dirname);
+}
+
+exports.exec = exec;
+/*
var _ = require('underscore'),
fs = require('fs'),
Jenkins = require('./jenkins').Jenkins,
@@ -107,4 +188,5 @@ function exec() {
nomnom.parseArgs();
}
-exports.exec = exec;
+exports.exec = exec;
+*/
View
64 lib/jenkins.js
@@ -1,4 +1,65 @@
var _ = require('underscore'),
+ request = require('request');
+
+function _request(method, url, resultCb, cb) {
+ request({
+ method: method,
+ uri: url
+ }, function (err, result) {
+ if (err) {
+ cb(err);
+ } else if (result.statusCode === 401 || result.statusCode === 403) {
+ cb(new Error('Jenkins requires authentication - set username and password in JENKINS_URL'));
+ } else {
+ resultCb(result);
+ }
+ });
+}
+
+function _status(color) {
+
+ var colors = {
+ 'blue': 'OK',
+ 'green': 'OK',
+ 'grey': 'ABORTED',
+ 'red': 'FAIL',
+ 'yellow': 'WARN'
+ };
+
+ // remove animation status (only for actively running job)
+ color = color.replace(/_anime/, '');
+
+ return (colors[color]) ? (colors[color]) : color.toUpperCase();
+}
+
+function Jenkins (url) {
+ this.url = url;
+}
+
+Jenkins.prototype.dashboard = function (cb) {
+ _request('get', this.url + '/api/json', function (result) {
+
+ var jobs = JSON.parse(result.body).jobs,
+ data = [];
+
+ if (!_.isEmpty(jobs)) {
+ jobs.forEach(function (job) {
+ data.push({ status: _status(job.color), name: job.name });
+ });
+ }
+ cb(null, data);
+
+ }, cb);
+};
+
+Jenkins.prototype.version = function (cb) {
+
+};
+
+module.exports = Jenkins;
+
+/*
+var _ = require('underscore'),
comm = require('./comm');
function Jenkins(url) {
@@ -92,7 +153,7 @@ function Jenkins(url) {
progress: executor.progress,
name: (!executor.idle) ?
executor.currentExecutable.url.replace(/.*\/job\//, '').
- replace(/\/.*/, '') : ''
+ replace(/\/.*TOREMOVE/, '') : ''
});
});
});
@@ -159,3 +220,4 @@ function Jenkins(url) {
}
exports.Jenkins = Jenkins;
+*/
View
15 package.json
@@ -1,10 +1,11 @@
{
"name": "nestor",
- "description": "Node.js Jenkins command-line interface",
+ "description": "Jenkins command-line interface in Node.js",
"keywords": [
"jenkins",
"ci",
- "command line"
+ "cli",
+ "command-line"
],
"version": "0.0.5",
"homepage": "http://github.com/cliffano/nestor",
@@ -25,13 +26,15 @@
"test": "./test"
},
"dependencies": {
- "nomnom": "1.5.1",
- "underscore": "1.2.3",
- "xml2js": "0.1.9"
+ "bagofholding": "0.0.4",
+ "request": "2.9.202",
+ "underscore": "1.3.3",
+ "xml2js": "0.1.14"
},
"devDependencies": {
+ "mocha": "1.0.3",
"sandboxed-module": "0.1.3",
- "vows": "0.6.1"
+ "should": "0.6.3"
},
"engines": {
"node": ">= 0.4.0 < 0.7.0"
View
164 test/jenkins.js
@@ -1,3 +1,164 @@
+var bag = require('bagofholding'),
+ sandbox = require('sandboxed-module'),
+ should = require('should'),
+ checks, mocks,
+ jenkins;
+
+describe('jenkins', function () {
+
+ function create(checks, mocks) {
+ return sandbox.require('../lib/jenkins', {
+ requires: mocks ? mocks.requires : {},
+ globals: {}
+ });
+ }
+
+ beforeEach(function () {
+ checks = {};
+ mocks = {};
+ });
+
+ describe('jenkins', function () {
+
+ it('should pass error to callback when an error occurs while sending request', function (done) {
+ mocks.request_err = new Error('someerror');
+ mocks.requires = {
+ request: bag.mock.request(checks, mocks)
+ };
+ jenkins = new (create(checks, mocks))();
+ jenkins.dashboard(function cb(err, result) {
+ checks.jenkins_dashboard_cb_args = cb['arguments'];
+ done();
+ });
+ checks.jenkins_dashboard_cb_args[0].message.should.equal('someerror');
+ should.not.exist(checks.jenkins_dashboard_cb_args[1]);
+ });
+
+ it('should pass authentication error to callback when result has status code 401', function (done) {
+ mocks.request_result = { statusCode: 401 };
+ mocks.requires = {
+ request: bag.mock.request(checks, mocks)
+ };
+ jenkins = new (create(checks, mocks))();
+ jenkins.dashboard(function cb(err, result) {
+ checks.jenkins_dashboard_cb_args = cb['arguments'];
+ done();
+ });
+ checks.jenkins_dashboard_cb_args[0].message.should.equal('Jenkins requires authentication - set username and password in JENKINS_URL');
+ should.not.exist(checks.jenkins_dashboard_cb_args[1]);
+ });
+
+ it('should pass authentication error to callback when result has status code 403', function (done) {
+ mocks.request_result = { statusCode: 403 };
+ mocks.requires = {
+ request: bag.mock.request(checks, mocks)
+ };
+ jenkins = new (create(checks, mocks))();
+ jenkins.dashboard(function cb(err, result) {
+ checks.jenkins_dashboard_cb_args = cb['arguments'];
+ done();
+ });
+ checks.jenkins_dashboard_cb_args[0].message.should.equal('Jenkins requires authentication - set username and password in JENKINS_URL');
+ should.not.exist(checks.jenkins_dashboard_cb_args[1]);
+ });
+ });
+
+ describe('dashboard', function () {
+
+ it('should return empty data when dashboard has no job', function (done) {
+ mocks.request_result = { statusCode: 200, body: '{ "jobs": [] }'};
+ mocks.requires = {
+ request: bag.mock.request(checks, mocks)
+ };
+ jenkins = new (create(checks, mocks))('http://localhost:8080');
+ jenkins.dashboard(function cb(err, result) {
+ checks.jenkins_dashboard_cb_args = cb['arguments'];
+ done();
+ });
+ should.not.exist(checks.jenkins_dashboard_cb_args[0]);
+ checks.jenkins_dashboard_cb_args[1].length.should.equal(0);
+ });
+
+ it('should return statuses when dashboard has jobs with known color value', function (done) {
+ mocks.request_result = { statusCode: 200, body: JSON.stringify(
+ { jobs: [
+ { name: 'job1', color: 'blue' },
+ { name: 'job2', color: 'green' },
+ { name: 'job3', color: 'grey' },
+ { name: 'job4', color: 'red' },
+ { name: 'job5', color: 'yellow' }
+ ]}
+ )};
+ mocks.requires = {
+ request: bag.mock.request(checks, mocks)
+ };
+ jenkins = new (create(checks, mocks))('http://localhost:8080');
+ jenkins.dashboard(function cb(err, result) {
+ checks.jenkins_dashboard_cb_args = cb['arguments'];
+ done();
+ });
+ should.not.exist(checks.jenkins_dashboard_cb_args[0]);
+ var jobs = checks.jenkins_dashboard_cb_args[1];
+ jobs.length.should.equal(5);
+ jobs[0].name.should.equal('job1');
+ jobs[0].status.should.equal('OK');
+ jobs[1].name.should.equal('job2');
+ jobs[1].status.should.equal('OK');
+ jobs[2].name.should.equal('job3');
+ jobs[2].status.should.equal('ABORTED');
+ jobs[3].name.should.equal('job4');
+ jobs[3].status.should.equal('FAIL');
+ jobs[4].name.should.equal('job5');
+ jobs[4].status.should.equal('WARN');
+ });
+
+ it('should return statuses when dashboard has running jobs with animated color value', function (done) {
+ mocks.request_result = { statusCode: 200, body: JSON.stringify(
+ { jobs: [
+ { name: 'job1', color: 'grey_anime' },
+ { name: 'job2', color: 'red_anime' }
+ ]}
+ )};
+ mocks.requires = {
+ request: bag.mock.request(checks, mocks)
+ };
+ jenkins = new (create(checks, mocks))('http://localhost:8080');
+ jenkins.dashboard(function cb(err, result) {
+ checks.jenkins_dashboard_cb_args = cb['arguments'];
+ done();
+ });
+ should.not.exist(checks.jenkins_dashboard_cb_args[0]);
+ var jobs = checks.jenkins_dashboard_cb_args[1];
+ jobs.length.should.equal(2);
+ jobs[0].name.should.equal('job1');
+ jobs[0].status.should.equal('ABORTED');
+ jobs[1].name.should.equal('job2');
+ jobs[1].status.should.equal('FAIL');
+ });
+
+ it('should return statuses when dashboard has jobs with unknown color value', function (done) {
+ mocks.request_result = { statusCode: 200, body: JSON.stringify(
+ { jobs: [
+ { name: 'job1', color: 'disabled' }
+ ]}
+ )};
+ mocks.requires = {
+ request: bag.mock.request(checks, mocks)
+ };
+ jenkins = new (create(checks, mocks))('http://localhost:8080');
+ jenkins.dashboard(function cb(err, result) {
+ checks.jenkins_dashboard_cb_args = cb['arguments'];
+ done();
+ });
+ should.not.exist(checks.jenkins_dashboard_cb_args[0]);
+ var jobs = checks.jenkins_dashboard_cb_args[1];
+ jobs.length.should.equal(1);
+ jobs[0].name.should.equal('job1');
+ jobs[0].status.should.equal('DISABLED');
+ });
+ });
+});
+/*
var assert = require('assert'),
jscoverageHack = require('../lib/jenkins'),
sandbox = require('sandboxed-module'),
@@ -276,4 +437,5 @@ vows.describe('jenkins').addBatch({
}
}
}
-}).exportTo(module);
+}).exportTo(module);
+*/

No commit comments for this range

Something went wrong with that request. Please try again.