From 5428347bfebf2a1689a2bb2d1433f4303354db56 Mon Sep 17 00:00:00 2001 From: oleg Date: Tue, 23 Jun 2015 22:18:13 +0300 Subject: [PATCH] catch revs by comment --- data/projects/project1/config.yaml | 3 + lib/executor/base.js | 37 ++++++++++- lib/executor/local.js | 31 ++++++--- lib/scm/base.js | 9 +++ lib/scm/mercurial.js | 65 +++++++++++++------ test/executor.js | 100 +++++++++++++++++++++++------ test/helpers.js | 20 ++++++ test/scm.js | 54 ++++++---------- 8 files changed, 233 insertions(+), 86 deletions(-) create mode 100644 test/helpers.js diff --git a/data/projects/project1/config.yaml b/data/projects/project1/config.yaml index 708247b..5d37f68 100644 --- a/data/projects/project1/config.yaml +++ b/data/projects/project1/config.yaml @@ -4,6 +4,9 @@ scm: repository: ./test/repos/mercurial rev: default +# catchRev: +# comment: !!js/regexp // + notify: on: # - done diff --git a/lib/executor/base.js b/lib/executor/base.js index c4cff73..252c81e 100644 --- a/lib/executor/base.js +++ b/lib/executor/base.js @@ -48,4 +48,39 @@ Executor.prototype.run = function(params, callback) { }, callback ); -}; \ No newline at end of file +}; + +// Returns target rev and filtered changes according to `catchRev` +Executor.prototype._getTarget = function(rev, changes) { + var result = {rev: rev, changes: changes}, + catchRev = this.project.catchRev; + + if (catchRev) { + // reverse before search + changes = changes.reverse(); + + var index; + + var comment = catchRev.comment; + if (comment) { + index = _(changes).findIndex(function(change) { + if (_(comment).isRegExp()) { + return comment.test(change.comment); + } else { + return comment === change.comment; + } + }); + } + + if (index !== -1) { + result.rev = changes[index].id; + result.changes = changes.slice(0, index); + result.changes.reverse(); + } + + // reverse back before return + changes = changes.reverse(); + } + + return result; +}; diff --git a/lib/executor/local.js b/lib/executor/local.js index 8f0d6ec..7010c68 100644 --- a/lib/executor/local.js +++ b/lib/executor/local.js @@ -53,18 +53,29 @@ Executor.prototype._getSources = function(params, callback) { } }, function() { - if (!isFirstRun) { - scm.update(params.rev, this.slot()); - } else { - this.pass(null); - } - }, - function() { - scm.getCurrent(this.slot()); scm.getChanges(oldRev && oldRev.id, params.rev, this.slot()); }, - function(err, rev, changes) { - this.pass({rev: rev, changes: changes}); + function(err, changes) { + var target = self._getTarget(params.rev, changes); + this.pass(target.changes); + scm.update(target.rev, this.slot()); + }, + function(err, changes) { + scm.getCurrent(this.slot()); + this.pass(changes); + scm.getRev(params.rev, this.slot()); + }, + function(err, rev, changes, latestRev) { + // add current rev to the lates changes (if it's not yet there) + if (changes.length && changes[0].id !== rev.id) { + changes.unshift(rev); + } + + this.pass({ + rev: rev, + changes: changes, + isLatest: changes.length && changes[0].id === latestRev.id + }); }, callback ); diff --git a/lib/scm/base.js b/lib/scm/base.js index 21d82cb..a626bef 100644 --- a/lib/scm/base.js +++ b/lib/scm/base.js @@ -40,6 +40,15 @@ Scm.prototype.getCurrent = function(callback) { Scm.prototype.getChanges = function(rev1, rev2, callback) { }; +/** + * Returns info (in changes format) about target revision + */ +Scm.prototype.getRev = function(rev, callback) { + this.getChanges(rev, rev, function(err, changes) { + callback(err, !err && changes[0]); + }); +}; + /** * Updates to revision */ diff --git a/lib/scm/mercurial.js b/lib/scm/mercurial.js index b329895..3392b1f 100644 --- a/lib/scm/mercurial.js +++ b/lib/scm/mercurial.js @@ -1,7 +1,9 @@ 'use strict'; var ParentScm = require('./base').Scm, - inherits = require('util').inherits; + inherits = require('util').inherits, + Steppy = require('twostep').Steppy, + _ = require('underscore'); function Scm(params) { ParentScm.call(this, params); @@ -29,13 +31,16 @@ Scm.prototype._parseRev = function(str) { Scm.prototype.clone = function(dst, rev, callback) { var self = this; - this.run({ - cmd: 'hg', - args: ['clone', '--rev', rev, this.repository, dst] - }, function(err) { - self.cwd = dst; - callback(err); - }); + Steppy( + function() { + self.run({ + cmd: 'hg', + args: ['clone', '--rev', rev, self.repository, dst] + }, this.slot()); + self.cwd = dst; + }, + callback + ); }; Scm.prototype.pull = function(rev, callback) { @@ -44,23 +49,41 @@ Scm.prototype.pull = function(rev, callback) { Scm.prototype.getCurrent = function(callback) { var self = this; - self.run({cmd: 'hg', args: [ - 'parent', '--template', self._revTemplate - ]}, function(err, stdout) { - callback(err, !err && self._parseRev(stdout)); - }); + Steppy( + function() { + self.run({cmd: 'hg', args: [ + 'parent', '--template', self._revTemplate + ]}, this.slot()); + }, + function(err, stdout) { + this.pass(self._parseRev(stdout)); + }, + callback + ); }; Scm.prototype.getChanges = function(rev1, rev2, callback) { var self = this; - self.run({cmd: 'hg', args: [ - 'log', '--rev', rev2 + ':' + rev1, - '--template', self._revTemplate + '\n' - ]}, function(err, stdout) { - callback(err, !err && stdout.split('\n').slice(0, -2).map(function(str) { - return self._parseRev(str); - })); - }); + Steppy( + function() { + self.run({cmd: 'hg', args: [ + 'log', '--rev', rev2 + ':' + rev1, + '--template', self._revTemplate + '\n' + ]}, this.slot()); + }, + function(err, stdout) { + // always skip last line - it's empty and also skip first + // rev if we see range + var rows = stdout.split('\n').slice(0, rev1 === rev2 ? -1 : -2); + + var changes = _(rows).map(function(str) { + return self._parseRev(str); + }); + + this.pass(changes); + }, + callback + ); }; Scm.prototype.update = function(rev, callback) { diff --git a/test/executor.js b/test/executor.js index 9260fa2..63e66fa 100644 --- a/test/executor.js +++ b/test/executor.js @@ -4,33 +4,34 @@ var expect = require('expect.js'), path = require('path'), fs = require('fs'), createExecutor = require('../lib/executor').createExecutor, - SpawnCommand = require('../lib/command/spawn').Command; + SpawnCommand = require('../lib/command/spawn').Command, + _ = require('underscore'), + mercurialRevs = _(require('./helpers').mercurialRevs).clone(); ['local'].forEach(function(type) { describe(type + ' executor', function() { var workspacePath = path.join(__dirname, 'workspace'); - function rmdir(dir, callback) { + var removeDir = function (dir, callback) { new SpawnCommand().run({cmd: 'rm', args: ['-R', dir]}, callback); } - it('remove test workspace dir if it exists', function(done) { + var clearWorkspace = function (done) { if (fs.exists(workspacePath, function(isExists) { if (isExists) { - rmdir(workspacePath, done); + removeDir(workspacePath, done); } else { done(); } })); - }); + } - var executor; - - it('instance should be created without errors', function() { - executor = createExecutor({ + var makeExecutorParams = function(params) { + params = params || {}; + return { type: type, - project: { + project: _({ dir: __dirname, name: 'test project', scm: { @@ -42,22 +43,81 @@ var expect = require('expect.js'), {type: 'shell', cmd: 'echo 1'}, {type: 'shell', cmd: 'echo 2'} ] - } + }).extend(params.project) + }; + }; + + var executor, scmData; + + describe('with scm rev default and without catch rev', function() { + before(clearWorkspace); + + it('instance should be created without errors', function() { + executor = createExecutor(makeExecutorParams()); + }); + + it('should run without errors', function(done) { + executor.run({}, function(err) { + expect(err).not.ok(); + done(); + }); + executor.on('scmData', function(data) { + scmData = data; + }); + }); + + it('scm data should be rev: 2, changes: [0-2], latest', function() { + expect(scmData).eql({ + rev: mercurialRevs[2], + changes: mercurialRevs.slice().reverse(), + isLatest: true + }); }); }); - it('should run', function() { - executor.run({}, function(err) { - expect(err).not.ok(); - }); - }); + describe('with scm rev default and catch rev "first revision"', function() { + before(clearWorkspace); - it('should emit scm data', function(done) { - executor.on('scmData', function(scmData) { - expect(scmData).have.keys('rev', 'changes'); - done(); + it('instance should be created without errors', function() { + executor = createExecutor(makeExecutorParams({ + project: { + catchRev: {comment: 'first revision'} + } + })); + }); + + it('should run without errors', function(done) { + executor.run({}, function(err) { + expect(err).not.ok(); + done(); + }); + executor.on('scmData', function(data) { + scmData = data; + }); + }); + + it('scm data should be rev: 1, changes: [0, 1], not latest', + function() { + expect(scmData).eql({ + rev: mercurialRevs[1], + changes: mercurialRevs.slice(0, 2).reverse(), + isLatest: false + }); + }); + + it('should run it again without errors', function(done) { + executor.run({}, done); + }); + + it('scm data should be rev: 2, changes: [2], latest', function() { + expect(scmData).eql({ + rev: mercurialRevs[2], + changes: mercurialRevs.slice(2, 3).reverse(), + isLatest: true + }); }); }); }); + }); diff --git a/test/helpers.js b/test/helpers.js new file mode 100644 index 0000000..7fac9b8 --- /dev/null +++ b/test/helpers.js @@ -0,0 +1,20 @@ +'use strict'; + + +// revisions for the test mercurial repo +exports.mercurialRevs = [{ + id: 'da2762e71e87', + author: 'kotbegemot', + date: new Date('Fri May 09 22:36:41 2014 +0400').getTime(), + comment: 'zero revision' +}, { + id: '98e3a18d8193', + author: 'kotbegemot', + date: new Date('Fri May 09 22:37:19 2014 +0400').getTime(), + comment: 'first revision' +}, { + id: '9d7d08445f4c', + author: 'kotbegemot', + date: new Date('Sat May 10 03:18:20 2014 +0400').getTime(), + comment: 'third revision' +}]; diff --git a/test/scm.js b/test/scm.js index 88ee687..e81b821 100644 --- a/test/scm.js +++ b/test/scm.js @@ -4,7 +4,8 @@ var expect = require('expect.js'), path = require('path'), fs = require('fs'), createScm = require('../lib/scm').createScm, - SpawnCommand = require('../lib/command/spawn').Command; + SpawnCommand = require('../lib/command/spawn').Command, + mercurialRevs = require('./helpers').mercurialRevs; ['mercurial'].forEach(function(type) { @@ -36,9 +37,9 @@ var expect = require('expect.js'), }); }); - var currentRev = data.rev0.id; + var currentRev = data[0].id; it('clone rev0 to dst without errors', function(done) { - scm.clone(repositoryPath, data.rev0.id, done); + scm.clone(repositoryPath, data[0].id, done); }); it('expect scm.cwd equals to dst', function() { @@ -48,13 +49,21 @@ var expect = require('expect.js'), it('expect current revision equals to rev0', function(done) { scm.getCurrent(function(err, rev) { if (err) return done(err); - expect(rev).eql(data.rev0); + expect(rev).eql(data[0]); + done(); + }); + }); + + it('expect rev0 info is good', function(done) { + scm.getRev(mercurialRevs[0].id, function(err, rev) { + if (err) return done(err); + expect(rev).eql(mercurialRevs[0]); done(); }); }); it('expect none changes from rev0 to default revision', function(done) { - scm.getChanges(data.rev0.id, scm.defaultRev, function(err, changes) { + scm.getChanges(data[0].id, scm.defaultRev, function(err, changes) { if (err) return done(err); expect(changes).ok(); expect(changes).length(0); @@ -68,11 +77,11 @@ var expect = require('expect.js'), 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) { + scm.getChanges(data[0].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]); + expect(changes).eql([data[2], data[1]]); done(); }); }); @@ -85,7 +94,7 @@ var expect = require('expect.js'), it('expect current revision equals to rev2', function(done) { scm.getCurrent(function(err, rev) { if (err) return done(err); - expect(rev).eql(data.rev2); + expect(rev).eql(data[2]); done(); }); }); @@ -96,11 +105,11 @@ var expect = require('expect.js'), it('expect repository log from rev0 to default revision equals to ' + 'rev1 and rev2 (in reverse order)', function(done) { - scm.getChanges(data.rev0.id, scm.defaultRev, function(err, changes) { + scm.getChanges(data[0].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]); + expect(changes).eql([data[2], data[1]]); done(); }); }); @@ -113,28 +122,5 @@ var expect = require('expect.js'), 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' - } - }; + if (type === 'mercurial') return mercurialRevs; }