Skip to content

Commit

Permalink
implement tasks. fixes #18
Browse files Browse the repository at this point in the history
  • Loading branch information
pstadler committed Jun 9, 2014
1 parent 6438a61 commit a769284
Show file tree
Hide file tree
Showing 6 changed files with 142 additions and 20 deletions.
40 changes: 37 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ $ npm install -g flightplan
$ npm install flightplan --save-dev

# run a flightplan (`fly --help` for more information)
$ fly <destination> [--plan flightplan.(js|coffee)]
$ fly [task:]<destination> [--plan flightplan.(js|coffee)]
```

By default, the `fly` command will look for `flightplan.js` or `flightplan.coffee`.
Expand Down Expand Up @@ -160,6 +160,34 @@ plan.local(function(transport) {});
// ...
```

### Tasks
Flightplan supports optional tasks to run a subset of flights.

```javascript
// fly deploy:<destination>
plan.local('deploy', function(transport) {});

// fly build:<destination>
plan.local('build', function(transport) {});

// fly deploy:<destination> or...
// fly build:<destination>
plan.local(['deploy', 'build'], function(transport) {});
plan.remote(['deploy', 'build'], function(transport) {});
```

If no task is specified it's implicitly set to "default". Therefore,
`fly <destination>` is the same as `fly default:<destination>`.

```javascript
// fly <destination>
plan.local(function(transport) {});
// is the same as...
plan.local('default', function(transport) {});
// "default" + other tasks:
plan.remote(['default', 'deploy', 'build'], function(transport) {});
```

### flightplan.briefing(config) → this

Configure the flightplan's destinations with `briefing()`. Without a
Expand Down Expand Up @@ -205,7 +233,7 @@ the `-u|--username` option:
fly production --username=admin
```

### flightplan.local(fn) → this
### flightplan.local([task|tasks, ]fn) → this

Calling this method registers a local flight. Local flights are
executed on your localhost. When `fn` gets called a `Transport` object
Expand All @@ -217,7 +245,10 @@ plan.local(function(local) {
});
```

### flightplan.remote(fn) → this
An optional first parameter of type Array or String can be passed for
defining the flight's task(s).

### flightplan.remote([task|tasks, ]fn) → this

Calling this method registers a remote flight. Remote
flights are executed on the current destination's remote hosts defined
Expand All @@ -230,6 +261,9 @@ plan.remote(function(remote) {
});
```

An optional first parameter of type Array or String can be passed for
defining the flight's task(s).

### flightplan.success(fn) → this

`fn()` is called after the flightplan (and therefore all flights)
Expand Down
13 changes: 10 additions & 3 deletions bin/fly.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ var path = require('path')
, version = require('../package.json').version;

program
.usage('<destination> [options]')
.usage('[task:]destination [options]')
.version(version)
.option('-p, --plan <file>', 'path to flightplan (default: flightplan.js)', 'flightplan.js')
.option('-u, --username <string>', 'user for connecting to remote hosts')
Expand Down Expand Up @@ -47,7 +47,14 @@ var flightplan = require(flightFile)
debug: program.debug || null
};

var destination = program.args[0];
var destination = program.args[0]
, task = 'default';

if(~(destination || '').indexOf(':')) {
var arr = destination.split(':');
task = arr[0];
destination = arr[1];
}

if(!flightplan.requiresDestination) {
logger.error(logger.format('%s is not a valid flightplan', program.plan.white));
Expand All @@ -60,4 +67,4 @@ if(!destination && flightplan.requiresDestination()) {
process.exit(1);
}

flightplan.start(destination, options);
flightplan.start(task, destination, options);
2 changes: 2 additions & 0 deletions gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ gulp.task('docs', function(taskFinished) {
, readmeStr = fs.readFileSync(readme, 'utf8');

docsStr = docsStr
.replace(/&lt;/g, "<")
.replace(/&gt;/g, ">")
.replace(/&#39;/g, "'")
.replace(/&quot;/g, '"')
.replace(/&amp;/g, '&');
Expand Down
102 changes: 90 additions & 12 deletions lib/flightplan.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,42 @@ var Fiber = require('fibers')
* // ...
* ```
*
* ### Tasks
* Flightplan supports optional tasks to run a subset of flights.
*
* ```javascript
* // fly deploy:<destination>
* plan.local('deploy', function(transport) {});
*
* // fly build:<destination>
* plan.local('build', function(transport) {});
*
* // fly deploy:<destination> or...
* // fly build:<destination>
* plan.local(['deploy', 'build'], function(transport) {});
* plan.remote(['deploy', 'build'], function(transport) {});
* ```
*
* If no task is specified it's implicitly set to "default". Therefore,
* `fly <destination>` is the same as `fly default:<destination>`.
*
* ```javascript
* // fly <destination>
* plan.local(function(transport) {});
* // is the same as...
* plan.local('default', function(transport) {});
* // "default" + other tasks:
* plan.remote(['default', 'deploy', 'build'], function(transport) {});
* ```
*
* @class Flightplan
* @return flightplan
*/
function Flightplan() {
this._briefing = null;
this.flights = [];
this.flights = {};
this.target = {
task: 'default',
destination: null,
hosts: []
};
Expand Down Expand Up @@ -164,11 +193,33 @@ Flightplan.prototype = {
* });
* ```
*
* @method local(fn)
* An optional first parameter of type Array or String can be passed for
* defining the flight's task(s).
*
* @method local([tasks, ]fn)
* @return this
*/
local: function(fn) {
this.flights.push(new LocalFlight(this, fn));
local: function() {
var args = Array.prototype.slice.call(arguments, 0);
var fn, tasks = [];

if(typeof args[0] === 'string') {
tasks.push(args[0]);
fn = args[1];
} else if(args[0] instanceof Array) {
tasks = args[0];
fn = args[1];
} else {
tasks.push('default');
}

var flight = new LocalFlight(this, fn || args[0]);

tasks.forEach(function(task) {
this.flights[task] = this.flights[task] || [];
this.flights[task].push(flight);
}.bind(this));

return this;
},

Expand All @@ -184,11 +235,33 @@ Flightplan.prototype = {
* });
* ```
*
* @method remote(fn)
* An optional first parameter of type Array or String can be passed for
* defining the flight's task(s).
*
* @method remote([tasks, ]fn)
* @return this
*/
remote: function(fn) {
this.flights.push(new RemoteFlight(this, fn));
remote: function() {
var args = Array.prototype.slice.call(arguments, 0);
var fn, tasks = [];

if(typeof args[0] === 'string') {
tasks.push(args[0]);
fn = args[1];
} else if(args[0] instanceof Array) {
tasks = args[0];
fn = args[1];
} else {
tasks.push('default');
}

var flight = new RemoteFlight(this, fn || args[0]);

tasks.forEach(function(task) {
this.flights[task] = this.flights[task] || [];
this.flights[task].push(flight);
}.bind(this));

this.hasRemoteFlights = true;
return this;
},
Expand Down Expand Up @@ -244,7 +317,8 @@ Flightplan.prototype = {
return this.hasRemoteFlights;
},

start: function(destination, options) {
start: function(task, destination, options) {
this.target.task = task;
this.target.destination = destination;

if(this.briefing()) {
Expand All @@ -257,22 +331,26 @@ Flightplan.prototype = {
this.logger.error((destination || '<empty>').warn, 'is not a valid destination');
process.exit(1);
}

var flightsForTask = this.flights[this.target.task] || [];
this.target.hosts = this.briefing().getHostsForDestination(this.target.destination);

if(this.isAborted()) {
this.logger.error('Flightplan aborted'.error);
process.exit(1);
}
this.logger.info('Executing flightplan with'.info, String(this.flights.length).magenta
, 'planned flight(s) to'.info, (this.target.destination || 'localhost').warn);
this.logger.info('Flying to'.info
, (this.target.task === 'default' ? '' : (this.target.task.warn + ':'))
+ (this.target.destination || 'localhost').warn
, 'with '.info + String(flightsForTask.length).magenta + ' flight(s)'.info);
this.logger.space();

new Fiber(function() {

var t = process.hrtime();

for(var i=0, len=this.flights.length; i < len; i++) {
var flight = this.flights[i];
for(var i=0, len=flightsForTask.length; i < len; i++) {
var flight = flightsForTask[i];

this.logger.info('Flight'.info, this.logger.format('%s/%s', i+1, len).magenta
, 'launched...'.info);
Expand Down
3 changes: 2 additions & 1 deletion lib/transport/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ Transport.prototype = {
* @method with(cmd|options[, options], fn)
*/
with: function() {
var previousExecWith = this._execWith;
var previousOptions = util._extend({}, this.options); // clone
var args = Array.prototype.slice.call(arguments, 0);

Expand All @@ -326,7 +327,7 @@ Transport.prototype = {
args[i]();
}
}
this._execWith = '';
this._execWith = previousExecWith;
this.options = previousOptions;
},

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "flightplan",
"description": "Library for streamlining application deployment or systems administration tasks",
"version": "0.3.4",
"version": "0.4.0",
"author": "Patrick Stadler <patrick.stadler@gmail.com>",
"keywords": [
"deploy",
Expand Down

0 comments on commit a769284

Please sign in to comment.