Permalink
Browse files

complete reboot

  • Loading branch information...
1 parent 137ee92 commit 0407a1513d6e5849c8cff3ce0be0fdcb6634396e @substack committed Feb 3, 2012
Showing with 0 additions and 331 deletions.
  1. +0 −54 README.markdown
  2. +0 −46 bin/cli.js
  3. +0 −185 lib/deploy.js
  4. +0 −46 package.json
View
@@ -1,54 +0,0 @@
-stagecoach
-==========
-
-Stagecoach is a git deploy server and http router for continuous deployment.
-
-When you `git push` to stagecoach, the code spins up on a new subdomain based on
-the commit hash.
-
-You can then alias commit hash domains to client-facing subdomains using custom
-routing logic to do feature splits, A/B tests, or incremental phased deployment.
-
-status
-======
-
-The first part of the CLI tool that hosts a git server over http and brings up
-new domains works.
-
-The ports are hard-coded which is lame. Authentication over basic auth needs to
-be implemented too.
-
-The API for modifying the routing logic needs merged from the old code into the
-bin script.
-
-get started
-===========
-
-Create a `deploy.json` file in a git repo with a `"start"` key:
-
-``` js
-{ "start" : "node server.js" }
-```
-
-The `"start"` command will be passed a port to listen on as its first argument.
-
-Fire up a new git deploy server using the `stagecoach` command:
-
- stagecoach
-
-Push to the deploy server from your repo:
-
- git push http://localhost:7070 master
-
-Navigate to the commit hash subdomain on the deploy server:
-
- curl -H host:f117c05cb138b360e2d4dcd5b354ab2a5408adeb.localhost localhost:7070
-
-Hooray it worked.
-
-TODO: feature routing
-
-license
-=======
-
-MIT/X11
View
@@ -1,46 +0,0 @@
-var argv = require('optimist').argv;
-var http = require('http');
-var url = require('url');
-
-var deploy = require('../lib/deploy')(argv._[0] || process.cwd());
-
-var bouncy = require('bouncy');
-bouncy(function (req, bounce) {
- bounce(deploy.routes[req.headers.host] || adminPort)
-}).listen(argv.port || 80);
-
-var adminPort = Math.floor(Math.random() * 5e4 + 1e4);
-http.createServer(function (req, res) {
- var u = url.parse(req.url);
-
- var auth = (function () {
- var m = (req.headers.authorization || '').match(/^basic (\S+)/i);
- if (!m) return;
- var pair = Buffer(m[1], 'base64').toString().split(':');
- return { username : pair[0], password : pair[1] };
- })();
-
- if (!auth) {
- res.statusCode = 401;
- res.setHeader('www-authenticate', 'basic');
- res.end('authorization required');
- }
- else if (!authorized(auth.username, auth.password)) {
- res.statusCode = 403;
- res.setHeader('www-authenticate', 'basic');
- res.end('invalid password');
- }
- else if (req.method === 'GET' && u.pathname === '/') {
- res.setHeader('content-type', 'application/json');
- res.write(JSON.stringify(deploy.routes, undefined, 2));
- res.end('\r\n');
- }
- else deploy.handle(req, res)
-}).listen(adminPort);
-
-function authorized (user, pass) {
- if (user === 'beep' && pass === 'boop') {
- return true;
- }
- return false;
-}
View
@@ -1,185 +0,0 @@
-var net = require('net');
-var fs = require('fs');
-var path = require('path');
-var EventEmitter = require('events').EventEmitter;
-
-var spawn = require('child_process').spawn;
-var exec = require('child_process').exec;
-
-var mkdirp = require('mkdirp');
-var chdir = require('chdir');
-
-var pushover = require('pushover');
-var gitEmit = require('git-emit');
-
-module.exports = function (opts) {
- if (typeof opts === 'string') {
- opts = { dir : opts };
- }
- if (typeof opts.dir === 'string') {
- opts.dir = {
- repo : opts.dir + '/repos',
- deploy : opts.dir + '/deploys',
- };
- }
- mkdirp.sync(opts.dir.repo, 0700);
- mkdirp.sync(opts.dir.deploy, 0700);
-
- return new Server(opts);
-};
-
-function Server (opts) {
- var self = this;
- self.routes = {};
- self.repoDir = opts.dir.repo;
- self.deployDir = opts.dir.deploy;
-
- self.repos = pushover(self.repoDir);
- self.repos.on('push', self.onpush.bind(self));
-
- self.git = fs.readdirSync(self.repoDir).reduce(function (acc, repo) {
- acc[repo] = gitEmit(path.join(self.repoDir, repo));
- acc[repo].on('update', self.onupdate.bind(self, repo));
- return acc;
- }, {});
-}
-
-Server.prototype = new EventEmitter;
-
-Server.prototype.handle = function () {
- return this.repos.handle.apply(this.repos, arguments);
-};
-
-Server.prototype.onupdate = function (repo, update) {
- var self = this;
- var branch = update.arguments[0].split('/')[2];
- var commit = update.arguments[2];
-
- var deployDir = path.join(self.deployDir, repo, commit);
- mkdirp(deployDir, 0700, function (err) {
- if (err) update.reject(500, err)
- else self.deploy(repo, branch, commit, function (err) {
- if (err) update.reject(500, err)
- else update.accept()
- });
- });
-};
-
-Server.prototype.onpush = function (repo) {
- var self = this;
- if (self.git[repo]) return;
-
- self.git[repo] = gitEmit(path.join(self.repoDir, repo));
- self.git[repo].on('update', self.onupdate.bind(self, repo))
-
- self.lastCommit(repo, function (commit) {
- self.onupdate(repo, {
- arguments : [ 'refs/head/master', null, commit ],
- accept : function () {},
- reject : function (code, err) {
- console.error([ code, err ].filter(Boolean).join(' '));
- },
- });
- });
-};
-
-Server.prototype.lastCommit = function (repo, cb) {
- chdir(path.join(this.repoDir, repo), function () {
- // grab the last commit
- var cmd = 'git log -n1 --pretty="format:%H"';
- exec(cmd, function (err, stdout, stderr) {
- var commit = stdout.trim();
- cb(commit);
- });
- });
-};
-
-Server.prototype.createDeployDir = function (repo, commit, cb) {
- var dir = path.join(this.deployDir, repo, commit);
- var ps = spawn('git', [ 'init', dir ]);
-
- ps.on('exit', function (code) {
- if (code !== 0) cb('clone exited with code ' + code);
- else cb(null, dir)
- });
-};
-
-Server.prototype.fetch = function (repo, commit, cb) {
- var repoDir = path.join(this.repoDir, repo);
- var dir = path.join(this.deployDir, commit);
-
- chdir(dir, function () {
- var ps = spawn('git', [ 'fetch', repoDir, commit ]);
- ps.stdout.pipe(process.stdout, { end : false });
- ps.stderr.pipe(process.stdout, { end : false });
-
- ps.on('exit', function (code) {
- if (code !== 0) cb('git fetch exited with non-zero status')
- else cb()
- });
- });
-};
-
-Server.prototype.checkout = function (repo, commit, cb) {
- var repoDir = path.join(this.repoDir, repo);
- var dir = path.join(this.deployDir, commit);
-
- chdir(dir, function () {
- var ps = spawn('git', [ 'checkout', commit ]);
- ps.stdout.pipe(process.stdout, { end : false });
- ps.stderr.pipe(process.stdout, { end : false });
-
- ps.on('exit', function (code) {
- if (code !== 0) cb('git fetch exited with non-zero status')
- else cb()
- });
- });
-};
-
-Server.prototype.clone = function (repo, commit) {
- var self = this;
-
- self.createDeployDir(repo, commit, function (err, dir) {
- if (err) cb(err)
- else self.fetch(repo, commit, function (err) {
- if (err) cb(err)
- else self.checkout(repo, commit, function (err) {
- if (err) cb(err)
- });
- });
- });
-};
-
-Server.prototype.deploy = function (repo, branch, commit, cb) {
- var self = this;
- var deployDir = path.join(self.deployDir, repo, commit);
- var repoDir = path.join(self.repoDir, repo);
-
-
- var jsonFile = path.join(deployDir, 'deploy.json');
-
- ps.on('exit', function (code) {
- if (code !== 0) cb('clone exited with code ' + code);
- else path.exists(jsonFile, function (ex) {
- if (!ex) cb('no deploy.json file present')
- else fs.readFile(jsonFile, function (err, body) {
- try { var config = JSON.parse(body) }
- catch (err) { return cb(err) }
- if (!config.start) return cb('no start field present')
-
- var port = Math.floor(Math.random() * 5e4 + 1e4);
- self.routes[commit] = port;
-
- chdir(deployDir, function () {
- var cmd = config.start.split(' ').concat(port);
- var ps = spawn(cmd[0], cmd.slice(1));
-
- ps.stdout.pipe(process.stdout, { end : false });
- ps.stderr.pipe(process.stdout, { end : false });
- });
-
- cb(null);
- });
- })
- });
-};
View
@@ -1,46 +0,0 @@
-{
- "name" : "stagecoach",
- "description" : "git-based zero-downtime continuous integration and deployment",
- "version" : "0.0.0",
- "repository" : {
- "type" : "git",
- "url" : "git://github.com/substack/stagecoach.git"
- },
- "bin" : {
- "stagecoach" : "bin/server.js"
- },
- "keywords" : [
- "continuous",
- "integration",
- "deployment",
- "staging",
- "deploy"
- ],
- "directories" : {
- "lib" : ".",
- "example" : "example",
- "test" : "test"
- },
- "scripts" : {
- "test" : "tap test/*.js"
- },
- "dependencies" : {
- "bouncy" : "1.0.x",
- "git-emit" : "0.0.x",
- "pushover" : "0.1.x",
- "mkdirp" : "0.2.x",
- "chdir" : "0.0.x"
- },
- "devDependencies" : {
- "tap" : "0.0.x"
- },
- "engines" : {
- "node" : ">=0.4.0"
- },
- "license" : "MIT",
- "author" : {
- "name" : "James Halliday",
- "email" : "mail@substack.net",
- "url" : "http://substack.net"
- }
-}

0 comments on commit 0407a15

Please sign in to comment.