add base scm class, mercurial class with tests

This commit is contained in:
oleg 2014-05-10 03:27:35 +04:00
parent a51adc69d4
commit dc00488eea
47 changed files with 316 additions and 0 deletions

72
lib/scm/base.js Normal file
View File

@ -0,0 +1,72 @@
'use strict';
var spawn = require('child_process').spawn,
EventEmitter = require('events').EventEmitter,
inherits = require('util').inherits;
function BaseScm(config) {
var self = this;
self.config = config;
['src'].forEach(function(key) {
if (key in self.config === false) throw new Error(key + ' is not set');
self[key] = self.config[key];
});
self.cwd = config.cwd;
}
module.exports = BaseScm;
inherits(BaseScm, EventEmitter);
BaseScm.prototype._exec = function(command, args, callback) {
var self = this,
stdout = '';
var cmd = spawn(command, args, {cwd: this.cwd});
cmd.stdout.on('data', function(data) {
if (self.isEmit) self.emit('stdout', data);
stdout += data;
});
cmd.stderr.on('data', function(data) {
callback(new Error('Scm outputs to stderr: ' + data));
cmd.kill();
});
cmd.on('exit', function(code) {
var err = null;
if (code !== 0) err = new Error(
'Scm command exits with non-zero code: ' + code
)
callback(err, stdout);
});
return cmd;
};
/**
* Clone repository to the `dst` update to `rev` and set `this.cwd` to `dst`
*/
BaseScm.prototype.clone = function(dst, rev, callback) {
};
/**
* Pull changes from remote repository without update
*/
BaseScm.prototype.pull = function(rev, callback) {
};
/**
* Returns string id of current revision
*/
BaseScm.prototype.getId = function(callback) {
};
/**
* Returns array of changes between revisions
*/
BaseScm.prototype.getChanges = function(rev1, rev2, callback) {
};
/**
* Updates to revision
*/
BaseScm.prototype.update = function(rev, callback) {
};

8
lib/scm/index.js Normal file
View File

@ -0,0 +1,8 @@
'use strict';
var path = require('path');
exports.createScm = function(config) {
var Constructor = require(path.join(__dirname, config.type));
return new Constructor(config);
};

53
lib/scm/mercurial.js Normal file
View File

@ -0,0 +1,53 @@
'use strict';
var BaseScm = require('./base'),
inherits = require('util').inherits;
function MercurialScm(config) {
BaseScm.call(this, config);
}
module.exports = MercurialScm;
inherits(MercurialScm, BaseScm);
MercurialScm.prototype.defaultRev = 'default';
MercurialScm.prototype.clone = function(dst, rev, callback) {
var self = this;
this._exec('hg', ['clone', '--rev', rev, this.src, dst], function(err) {
self.cwd = dst;
callback(err);
});
};
MercurialScm.prototype.pull = function(rev, callback) {
this._exec('hg', ['pull', '--rev', rev], callback);
};
MercurialScm.prototype.getId = function(callback) {
this._exec('hg', ['id', '--id'], function(err, stdout) {
callback(err, !err && stdout.replace('\n', ''));
});
};
MercurialScm.prototype.getChanges = function(rev1, rev2, callback) {
this._exec('hg', [
'log', '--rev', rev2 + ':' + rev1,
'--template', '{node|short};;;{author};;;{date|date};;;{desc}\n'
], function(err, stdout) {
callback(err, !err && stdout.split('\n').slice(0, -2).map(function(str) {
var parts = str.split(';;;');
return {
id: parts[0],
author: parts[1],
date: new Date(parts[2]).getTime(),
comment: parts[3]
};
}));
});
};
MercurialScm.prototype.update = function(rev, callback) {
this._exec('hg', ['up', rev], callback);
};

35
package.json Normal file
View File

@ -0,0 +1,35 @@
{
"name": "nci",
"version": "0.1.0-alpha",
"description": "Continuous integration server written in node.js",
"bin": {
"nci": "bin/nci"
},
"scripts": {
"test": "mocha --bail --reporter=spec test"
},
"repository": {
"type": "git",
"url": "git://github.com/okv/nci.git"
},
"keywords": [
"continuous",
"integration",
"server",
"ci",
"build"
],
"author": "Oleg Korobenko <oleg.korobenko@gmail.com>",
"license": "MIT",
"bugs": {
"url": "https://github.com/okv/nci/issues"
},
"homepage": "https://github.com/okv/nci",
"dependencies": {
"twostep": "0.4.1"
},
"devDependencies": {
"expect.js": "0.3.1",
"mocha": "1.18.2"
}
}

Binary file not shown.

1
test/repos/.hg/branch Normal file
View File

@ -0,0 +1 @@
default

View File

@ -0,0 +1,2 @@
98e3a18d8193d36caf143e9b57f5123bfd5878c9 1
98e3a18d8193d36caf143e9b57f5123bfd5878c9 default

2
test/repos/.hg/cache/tags vendored Normal file
View File

@ -0,0 +1,2 @@
1 98e3a18d8193d36caf143e9b57f5123bfd5878c9

BIN
test/repos/.hg/dirstate Normal file

Binary file not shown.

4
test/repos/.hg/requires Normal file
View File

@ -0,0 +1,4 @@
dotencode
fncache
revlogv1
store

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,2 @@
data/rev0.txt.i
data/rev1.txt.i

View File

BIN
test/repos/.hg/store/undo Normal file

Binary file not shown.

View File

View File

View File

@ -0,0 +1 @@
default

3
test/repos/.hg/undo.desc Normal file
View File

@ -0,0 +1,3 @@
0
pull
file:///mnt/data/home/oleg/work/repository/git-hub/nci/test/repos/mercurial

View File

Binary file not shown.

View File

@ -0,0 +1,2 @@
9d7d08445f4ce095c22a98a902a391973cf07f37 2
9d7d08445f4ce095c22a98a902a391973cf07f37 default

2
test/repos/mercurial/.hg/cache/tags vendored Normal file
View File

@ -0,0 +1,2 @@
2 9d7d08445f4ce095c22a98a902a391973cf07f37

Binary file not shown.

View File

@ -0,0 +1 @@
third revision

View File

@ -0,0 +1,4 @@
dotencode
fncache
revlogv1
store

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,3 @@
data/rev0.txt.i
data/rev1.txt.i
data/rev2.txt.i

View File

@ -0,0 +1 @@
1 da2762e71e87935198a25b0fceab0a364ad2e6d7

Binary file not shown.

View File

@ -0,0 +1 @@
1 da2762e71e87935198a25b0fceab0a364ad2e6d7

View File

View File

@ -0,0 +1 @@
default

View File

@ -0,0 +1,2 @@
2
commit

Binary file not shown.

View File

View File

View File

0
test/repos/rev0.txt Normal file
View File

0
test/repos/rev1.txt Normal file
View File

116
test/scm.js Normal file
View File

@ -0,0 +1,116 @@
'use strict';
var expect = require('expect.js'),
path = require('path'),
fs = require('fs'),
createScm = require('../lib/scm').createScm;
['mercurial'].forEach(function(type) {
describe(type, function() {
var data = getTestData(type),
repositoryName = 'test-repository',
repositoryPath = path.join(path.join(__dirname, 'repos'), repositoryName);
it('remove test repository dir if it exists', function(done) {
if (fs.exists(repositoryPath, function(isExists) {
if (isExists) {
scm._exec('rm', ['-R', repositoryPath], done);
} else {
done();
}
}));
});
var scm = createScm({
type: type,
src: path.join(__dirname, 'repos', type)
});
var currentRev = data.rev0.id;
it('clone rev0 to dst without errors', function(done) {
scm.clone(repositoryPath, data.rev0.id, done);
});
it('expect scm.cwd equals to dst', function() {
expect(scm.cwd).equal(repositoryPath);
});
it('expect current id equals to rev0', function(done) {
scm.getId(function(err, id) {
if (err) return done(err);
expect(id).equal(data.rev0.id);
done();
});
});
it('expect none changes from rev0 to default revision', function(done) {
scm.getChanges(data.rev0.id, scm.defaultRev, function(err, changes) {
if (err) return done(err);
expect(changes).ok();
expect(changes).length(0);
done();
});
});
it('pull to default revision without errors', function(done) {
scm.pull(scm.defaultRev, done);
});
it('now (after pull) expect rev1 and rev2 as new changes (in reverse ' +
'order) from rev0 to default revision', function(done) {
scm.getChanges(data.rev0.id, scm.defaultRev, function(err, changes) {
if (err) return done(err);
expect(changes).ok();
expect(changes).length(2);
expect(changes).eql([data.rev2, data.rev1]);
done();
});
});
it('update to default revision (should update to rev2) without error',
function(done) {
scm.update(scm.defaultRev, done);
});
it('expect current revision equals to rev2', function(done) {
scm.getId(function(err, id) {
if (err) return done(err);
expect(id).equal(data.rev2.id);
done();
});
});
it('remove test repository dir', function(done) {
scm._exec('rm', ['-R', repositoryPath], done);
});
});
});
function getTestData(type) {
if (type === 'mercurial') return getMercurialData();
}
function getMercurialData() {
return {
rev0: {
id: 'da2762e71e87',
author: 'kotbegemot',
date: new Date('Fri May 09 22:36:41 2014 +0400').getTime(),
comment: 'zero revision'
},
rev1: {
id: '98e3a18d8193',
author: 'kotbegemot',
date: new Date('Fri May 09 22:37:19 2014 +0400').getTime(),
comment: 'first revision'
},
rev2: {
id: '9d7d08445f4c',
author: 'kotbegemot',
date: new Date('Sat May 10 03:18:20 2014 +0400').getTime(),
comment: 'third revision'
}
};
}