From 1031af3dbc0fc75eacd7e7adb077cb39bd943d2c Mon Sep 17 00:00:00 2001 From: Mat Scales Date: Tue, 30 Apr 2013 11:23:28 +0100 Subject: [PATCH] Allow a commit hash instead of a semver version (#275) --- lib/core/package.js | 60 +++++++++++++++++++++++++++++++-------------- test/package.js | 42 +++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 19 deletions(-) diff --git a/lib/core/package.js b/lib/core/package.js index 05f04fc3..2ae9b9ca 100755 --- a/lib/core/package.js +++ b/lib/core/package.js @@ -666,6 +666,34 @@ Package.prototype.checkout = function () { template('action', { name: 'fetching', shizzle: this.name }) .on('data', this.emit.bind(this, 'data')); + var doCheckout = function () { + template('action', { + name: 'checking out', + shizzle: this.name + '#' + this.tag + }).on('data', this.emit.bind(this, 'data')); + + // Checkout the tag + git([ 'checkout', this.tag, '-f'], { cwd: this.path }, this).on('close', function (code) { + if (code) return; + // Ensure that checkout the tag as it is, removing all untracked files + git(['clean', '-f', '-d'], { cwd: this.path }, this).on('close', function (code) { + if (code) return; + this.emit('checkout'); + this.loadJSON(); + }.bind(this)); + }.bind(this)); + }.bind(this); + + if (this.tag && !semver.validRange(this.tag)) { + // We might have a commit. Check that this is a valid commit SHA + return this.validCommit(this.tag, function (isValid) { + if (!isValid) { + return this.emit('error', new Error('Tag ' + this.tag + ' is not a valid semver range/version or a valid commit hash')); + } + doCheckout(); + }.bind(this)); + } + this.once('versions', function (versions) { if (!versions.length) { this.emit('checkout'); @@ -674,10 +702,6 @@ Package.prototype.checkout = function () { // If tag is specified, try to satisfy it if (this.tag) { - if (!semver.validRange(this.tag)) { - return this.emit('error', new Error('Tag ' + this.tag + ' is not a valid semver range/version')); - } - versions = versions.filter(function (version) { return semver.satisfies(version, this.tag); }.bind(this)); @@ -694,25 +718,23 @@ Package.prototype.checkout = function () { if (!semver.valid(this.tag)) this.commit = this.tag; // If the version is not valid, then its a commit if (this.tag) { - template('action', { - name: 'checking out', - shizzle: this.name + '#' + this.tag - }).on('data', this.emit.bind(this, 'data')); - - // Checkout the tag - git([ 'checkout', this.tag, '-f'], { cwd: this.path }, this).on('close', function (code) { - if (code) return; - // Ensure that checkout the tag as it is, removing all untracked files - git(['clean', '-f', '-d'], { cwd: this.path }, this).on('close', function (code) { - if (code) return; - this.emit('checkout'); - this.loadJSON(); - }.bind(this)); - }.bind(this)); + doCheckout(); } }).versions(); }; +Package.prototype.validCommit = function (hash, callback) { + var emitter = new events.EventEmitter(); + var cp = git(['branch', '-q', '--contains', hash], { cwd: this.gitPath }, emitter); + cp.on('close', function (code) { + if (code) callback(false); + callback(true); + }); + emitter.on('error', function () { + callback(false); + }); +}; + Package.prototype.describeTag = function () { var cp = git(['describe', '--always', '--tag'], { cwd: this.gitPath || this.path, ignoreCodes: [128] }, this); var tag = ''; diff --git a/test/package.js b/test/package.js index 3775574f..3e305887 100644 --- a/test/package.js +++ b/test/package.js @@ -682,4 +682,46 @@ describe('package', function () { pkg.resolve(); }); + + it('Should give a meaningful error if the commit does not exist', function (next) { + var commit = '000002a7b4e31cad48886d67446eb31faad92683'; + var pkg = new Package('jquery', 'git://github.com/maccman/package-jquery.git#' + commit); + + pkg.on('resolve', function () { + pkg.install(); + }); + + pkg.on('error', function (err) { + assert(/not a valid semver range\/version or a valid commit hash/.test(err.message)); + next(); + }); + + pkg.on('checkout', function () { + assert(false); + next(); + }); + + pkg.resolve(); + }); + + it('Should allow you to specify a git commit rather than a tag version', function (next) { + var commit = 'd54062a7b4e31cad48886d67446ea31faad92683'; + var pkg = new Package('jquery', 'git://github.com/maccman/package-jquery.git#' + commit); + + pkg.on('resolve', function () { + pkg.install(); + }); + + pkg.on('error', function (err) { + throw err; + }); + + pkg.on('checkout', function () { + assert(fs.existsSync(pkg.gitPath)); + assert.equal(fs.readFileSync(path.join(pkg.gitPath, '.git/HEAD'), 'UTF-8'), commit + '\n'); + next(); + }); + + pkg.resolve(); + }); });