mirror of
https://github.com/scratchfoundation/gh-pages.git
synced 2025-03-14 06:29:51 -04:00
Setup
This commit is contained in:
commit
47038707ba
8 changed files with 396 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/node_modules/
|
20
.jshintrc
Normal file
20
.jshintrc
Normal file
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"curly": true,
|
||||
"eqeqeq": true,
|
||||
"indent": 2,
|
||||
"latedef": true,
|
||||
"newcap": true,
|
||||
"nonew": true,
|
||||
"quotmark": "single",
|
||||
"undef": true,
|
||||
"trailing": true,
|
||||
"maxlen": 80,
|
||||
"globals": {
|
||||
"Buffer": false,
|
||||
"exports": true,
|
||||
"module": false,
|
||||
"process": false,
|
||||
"require": false,
|
||||
"__dirname": false
|
||||
}
|
||||
}
|
241
lib/git.js
Normal file
241
lib/git.js
Normal file
|
@ -0,0 +1,241 @@
|
|||
var cp = require('child_process');
|
||||
var path = require('path');
|
||||
var util = require('util');
|
||||
|
||||
var Q = require('q');
|
||||
var fs = require('q-io/fs');
|
||||
|
||||
var git = 'git';
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param {number} code Error code.
|
||||
* @param {string} message Error message.
|
||||
*/
|
||||
function ProcessError(code, message) {
|
||||
var callee = arguments.callee;
|
||||
Error.apply(this, [message]);
|
||||
Error.captureStackTrace(this, callee);
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
this.name = callee.name;
|
||||
}
|
||||
util.inherits(ProcessError, Error);
|
||||
|
||||
|
||||
/**
|
||||
* Util function for handling spawned processes as promises.
|
||||
* @param {string} exe Executable.
|
||||
* @param {Array.<string>} args Arguments.
|
||||
* @param {string} cwd Working directory.
|
||||
* @return {Promise} A promise.
|
||||
*/
|
||||
function spawn(exe, args, cwd) {
|
||||
var deferred = Q.defer();
|
||||
var child = cp.spawn(exe, args, {cwd: cwd || process.cwd()});
|
||||
var buffer = [];
|
||||
child.stderr.on('data', function(chunk) {
|
||||
buffer.push(chunk.toString());
|
||||
});
|
||||
child.stdout.on('data', function(chunk) {
|
||||
deferred.notify(chunk);
|
||||
});
|
||||
child.on('close', function(code) {
|
||||
if (code) {
|
||||
var msg = buffer.join('') || 'Process failed: ' + code;
|
||||
deferred.reject(new ProcessError(code, msg));
|
||||
} else {
|
||||
deferred.resolve(code);
|
||||
}
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Execute a git command.
|
||||
* @param {Array.<string>} args Arguments (e.g. ['remote', 'update']).
|
||||
* @param {string} cwd Repository directory.
|
||||
* @return {Promise} A promise. The promise will be resolved with the exit code
|
||||
* or rejected with an error. To get stdout, use a progress listener (e.g.
|
||||
* `promise.progress(function(chunk) {console.log(String(chunk);}))`).
|
||||
*/
|
||||
exports = module.exports = function(args, cwd) {
|
||||
return spawn(git, args, cwd);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Set the Git executable to be used by exported methods (defaults to 'git').
|
||||
* @param {string} exe Git executable (full path if not already on path).
|
||||
*/
|
||||
exports.exe = function(exe) {
|
||||
git = exe;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Initialize repository.
|
||||
* @param {string} cwd Repository directory.
|
||||
* @return {ChildProcess} Child process.
|
||||
*/
|
||||
exports.init = function init(cwd) {
|
||||
return spawn(git, ['init'], cwd);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clone a repo into the given dir if it doesn't already exist.
|
||||
* @param {string} repo Repository URL.
|
||||
* @param {string} dir Target directory.
|
||||
* @param {string} branch Branch name.
|
||||
* @param {options} options All options.
|
||||
* @return {Promise} A promise.
|
||||
*/
|
||||
exports.clone = function clone(repo, dir, branch, options) {
|
||||
return fs.exists(dir).then(function(exists) {
|
||||
if (exists) {
|
||||
return Q.resolve();
|
||||
} else {
|
||||
return fs.makeTree(path.dirname(path.resolve(dir))).then(function() {
|
||||
var args = ['clone', repo, dir, '--branch', branch, '--single-branch'];
|
||||
if (options.depth) {
|
||||
args.push('--depth', options.depth);
|
||||
}
|
||||
return spawn(git, args).fail(function(err) {
|
||||
// try again without banch options
|
||||
return spawn(git, ['clone', repo, dir]);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clean up unversioned files.
|
||||
* @param {string} cwd Repository directory.
|
||||
* @return {Promise} A promise.
|
||||
*/
|
||||
var clean = exports.clean = function clean(cwd) {
|
||||
return spawn(git, ['clean', '-f', '-d'], cwd);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Hard reset to remote/branch
|
||||
* @param {string} remote Remote alias.
|
||||
* @param {string} branch Branch name.
|
||||
* @param {string} cwd Repository directory.
|
||||
* @return {Promise} A promise.
|
||||
*/
|
||||
var reset = exports.reset = function reset(remote, branch, cwd) {
|
||||
return spawn(git, ['reset', '--hard', remote + '/' + branch], cwd);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Fetch from a remote.
|
||||
* @param {string} remote Remote alias.
|
||||
* @param {string} cwd Repository directory.
|
||||
* @return {Promise} A promise.
|
||||
*/
|
||||
exports.fetch = function fetch(remote, cwd) {
|
||||
return spawn(git, ['fetch', remote], cwd);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Checkout a branch (create an orphan if it doesn't exist on the remote).
|
||||
* @param {string} remote Remote alias.
|
||||
* @param {string} branch Branch name.
|
||||
* @param {string} cwd Repository directory.
|
||||
* @return {Promise} A promise.
|
||||
*/
|
||||
exports.checkout = function checkout(remote, branch, cwd) {
|
||||
var treeish = remote + '/' + branch;
|
||||
return spawn(git, ['ls-remote', '--exit-code', '.', treeish], cwd)
|
||||
.then(function() {
|
||||
// branch exists on remote, hard reset
|
||||
return spawn(git, ['checkout', branch], cwd)
|
||||
.then(function() {
|
||||
return clean(cwd);
|
||||
})
|
||||
.then(function() {
|
||||
return reset(remote, branch, cwd);
|
||||
});
|
||||
}, function(error) {
|
||||
if (error instanceof ProcessError && error.code === 2) {
|
||||
// branch doesn't exist, create an orphan
|
||||
return spawn(git, ['checkout', '--orphan', branch], cwd);
|
||||
} else {
|
||||
// unhandled error
|
||||
return Q.reject(error);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Remove all unversioned files.
|
||||
* @param {string} files Files argument.
|
||||
* @param {string} cwd Repository directory.
|
||||
* @return {Promise} A promise.
|
||||
*/
|
||||
exports.rm = function rm(files, cwd) {
|
||||
return spawn(git, ['rm', '--ignore-unmatch', '-r', '-f', files], cwd);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Add files.
|
||||
* @param {string} files Files argument.
|
||||
* @param {string} cwd Repository directory.
|
||||
* @return {Promise} A promise.
|
||||
*/
|
||||
exports.add = function add(files, cwd) {
|
||||
return spawn(git, ['add', files], cwd);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Commit.
|
||||
* @param {string} message Commit message.
|
||||
* @param {string} cwd Repository directory.
|
||||
* @return {Promise} A promise.
|
||||
*/
|
||||
exports.commit = function commit(message, cwd) {
|
||||
return spawn(git, ['diff-index', '--quiet', 'HEAD', '.'], cwd)
|
||||
.then(function() {
|
||||
// nothing to commit
|
||||
return Q.resolve();
|
||||
})
|
||||
.fail(function() {
|
||||
return spawn(git, ['commit', '-m', message], cwd);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Add tag
|
||||
* @param {string} name Name of tag.
|
||||
* @param {string} cwd Repository directory.
|
||||
* @return {Promise} A promise.
|
||||
*/
|
||||
exports.tag = function tag(name, cwd) {
|
||||
return spawn(git, ['tag', name], cwd);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Push a branch.
|
||||
* @param {string} remote Remote alias.
|
||||
* @param {string} branch Branch name.
|
||||
* @param {string} cwd Repository directory.
|
||||
* @return {Promise} A promise.
|
||||
*/
|
||||
exports.push = function push(remote, branch, cwd) {
|
||||
return spawn(git, ['push', '--tags', remote, branch], cwd);
|
||||
};
|
6
lib/index.js
Normal file
6
lib/index.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
|
||||
|
||||
/**
|
||||
* Generate promises for spawned git commands.
|
||||
*/
|
||||
exports.git = require('./git');
|
41
package.json
Normal file
41
package.json
Normal file
|
@ -0,0 +1,41 @@
|
|||
{
|
||||
"name": "gh-pages",
|
||||
"version": "0.0.0",
|
||||
"description": "Publish to a gh-pages branch on GitHub (or any other branch on any other remote)",
|
||||
"keywords": [
|
||||
"git",
|
||||
"gh-pages",
|
||||
"github"
|
||||
],
|
||||
"author": {
|
||||
"name": "Tim Schaub",
|
||||
"url": "http://tschaub.net/"
|
||||
},
|
||||
"licenses": [
|
||||
{
|
||||
"type": "MIT",
|
||||
"url": "http://tschaub.mit-license.org/"
|
||||
}
|
||||
],
|
||||
"homepage": "https://github.com/tschaub/gh-pages",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/tschaub/gh-pages.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/tschaub/gh-pages/issues"
|
||||
},
|
||||
"main": "lib/index.js",
|
||||
"scripts": {
|
||||
"test": "node tasks.js lint test"
|
||||
},
|
||||
"dependencies": {
|
||||
"q": "~1.0.1",
|
||||
"q-io": "~1.11.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"glob": "~3.2.9",
|
||||
"mocha": "~1.18.2",
|
||||
"jshint": "~2.4.4"
|
||||
}
|
||||
}
|
5
readme.md
Normal file
5
readme.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
# `gh-pages`
|
||||
|
||||
Publish files to a `gh-pages` branch on GitHub (or any other branch anywhere else).
|
||||
|
||||
This will evolve into a more useful package. For now, it just some extracted bits from the [`grunt-gh-pages`](https://www.npmjs.org/package/grunt-gh-pages) package.
|
56
tasks.js
Normal file
56
tasks.js
Normal file
|
@ -0,0 +1,56 @@
|
|||
var path = require('path');
|
||||
|
||||
var jshint = require('jshint/src/cli').run;
|
||||
var glob = require('glob');
|
||||
var Mocha = require('mocha');
|
||||
|
||||
|
||||
/**
|
||||
* Run the linter.
|
||||
* @param {function(Error)} done Callback.
|
||||
*/
|
||||
exports.lint = function(done) {
|
||||
var args = ['lib', 'test', 'tasks.js'];
|
||||
var passed = jshint({args: args});
|
||||
process.nextTick(function() {
|
||||
done(passed ? null : new Error('JSHint failed'));
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Run the tests.
|
||||
* @param {function(Error)} done Callback.
|
||||
*/
|
||||
exports.test = function(done) {
|
||||
var mocha = new Mocha();
|
||||
mocha.reporter('spec');
|
||||
mocha.ui('bdd');
|
||||
mocha.files = glob.sync('test/**/*.spec.js').map(function(file) {
|
||||
return path.resolve(file);
|
||||
});
|
||||
mocha.run(function(failures) {
|
||||
done(failures ? new Error('Mocha failures') : null);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
var tasks = process.argv.slice(2);
|
||||
|
||||
function run(current) {
|
||||
var task = tasks[current];
|
||||
if (task) {
|
||||
exports[task](function(err) {
|
||||
if (err) {
|
||||
process.stderr.write(err.message + '\n');
|
||||
process.exit(1);
|
||||
} else {
|
||||
++current;
|
||||
run(current);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
process.exit(0);
|
||||
}
|
||||
}
|
||||
run(0);
|
26
test/.jshintrc
Normal file
26
test/.jshintrc
Normal file
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"curly": true,
|
||||
"eqeqeq": true,
|
||||
"indent": 2,
|
||||
"latedef": true,
|
||||
"newcap": true,
|
||||
"nonew": true,
|
||||
"quotmark": "single",
|
||||
"undef": true,
|
||||
"trailing": true,
|
||||
"maxlen": 80,
|
||||
"globals": {
|
||||
"Buffer": false,
|
||||
"exports": true,
|
||||
"before": false,
|
||||
"beforeEach": false,
|
||||
"after": false,
|
||||
"afterEach": false,
|
||||
"describe": false,
|
||||
"it": false,
|
||||
"module": false,
|
||||
"process": false,
|
||||
"require": false,
|
||||
"__dirname": false
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue