cin
Version:
Lightweight, flexible continuous integration server for Git projects
203 lines (169 loc) • 4.04 kB
JavaScript
/**
* Module dependencies.
*/
var path = require('path')
, helper = require('./helper')
, Project = require('./project');
/**
* Expose `Cin`.
*/
module.exports = Cin;
/**
* Config defaults.
*/
var configFilename = '.cin-server.json'
, configDefaults = {
environments: {
node: 'nvm'
, ruby: 'rbenv'
}
, builds: {
concurency: 2
}
};
/**
* Initialize `Cin` with the given `options`.
*
* Options:
*
* - `workingPath` the working path for commands
*
* @param {Object} options
* @api private
*/
function Cin(options) {
var defaults = {
workingPath: process.cwd()
};
this.options = helper.merge(defaults, options);
this.workingPath = this.options.workingPath;
this.projectsPath = path.join(this.workingPath, 'projects');
this.configFilePath = path.join(this.workingPath, configFilename);
}
/**
* Check with Cin is installed in the current working path.
*
* @return {Boolean}
* @api private
*/
Cin.prototype.installed = function() {
return path.existsSync(this.configFilePath);
}
/**
* Install Cin at the current working path, calling `cb` when complete.
*
* @param {Function} cb
* @return {this}
* @api private
*/
Cin.prototype.install = function(cb) {
if(this.installed()) {
throw new Error('Cin already installed.');
}
var self = this;
helper.mkdir(this.workingPath, function() {
helper.mkdir(self.projectsPath);
helper.writeJSON(self.configFilePath, configDefaults);
return cb && cb(null, this);
});
return this;
}
/**
* Return a `Project` for the given `name`. It may or may not exist.
*
* `name` may take the following forms:
*
* - kainosnoema/cin
* - kainosnoema/cin@master
* - git@github.com:kainosnoema/cin.git
*
*
* @param {String} name
* @return {this}
* @api private
*/
Cin.prototype.project = function(name) {
this.assertInstalled();
return new Project(this.resolveAlias(name), this);
}
/**
* Get all the projects in the given current directory.
*
* @return {Array}
* @api private
*/
Cin.prototype.__defineGetter__("projects", function() {
return Project.all(this);
});
/**
* Create and checkout a project for the given `name` (see above),
* and sets configuration from `options` (see Project#create).
*
* @param {String} name
* @return {this}
* @api private
*/
Cin.prototype.add = function(name, options) {
return this.project(name).create(options);
}
/**
* Remove the project for the given `name`. rm -rf's the directory,
* so there's no undo for this.
*
* @param {String} name
* @return {this}
* @api private
*/
Cin.prototype.remove = function(name) {
this.project(name).destroy();
}
/**
* Returns a `Build` for the project for the given name, at the given `ref`.
*
* @param {String} name
* @param {String} ref
* @return {this}
* @api private
*/
Cin.prototype.build = function(name, ref) {
return this.project(name).build(ref);
}
/**
* Runs a build for the project for the given `name`, at the given `ref`,
* calling `cb` when complete.
*
* @param {String} name
* @param {String} ref
* @return {this}
* @api private
*/
Cin.prototype.run = function(name, ref, cb) {
return this.build(name, ref).run(cb);
}
/**
* Resolve a given project `name` as a potential alias. Preserves any
* specified refs after the project name.
*
* @param {String} name
* @return {this}
* @api private
*/
Cin.prototype.resolveAlias = function(name) {
if(name instanceof Project) { return name; }
var head = name.split('@')[1]
, alias = name.split('@')[0]
, match = this.projects.filter(function(project) {
return project.config.alias === alias;
})[0];
if(match) { return match.name + '@' + (head || 'master'); }
return name;
}
/**
* Assert that cin is installed.
*/
Cin.prototype.assertInstalled = function() {
if(!this.installed()) {
throw new Error('Cin not installed at current working path. ' +
'Run `cin install .` or change working paths.');
}
}