Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
dvonlehman committed Oct 25, 2016
0 parents commit 8e90f22
Show file tree
Hide file tree
Showing 11 changed files with 554 additions and 0 deletions.
42 changes: 42 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"extends": "airbnb-base",
"rules": {
"id-length": 0,
"comma-dangle": 0,
"vars-on-top": 0,
"func-names": 0,
"one-var": 0,
"no-use-before-define": [2, "nofunc"],
"new-cap": [2, { "capIsNewExceptions": ["Readable", "Writable"] }],
"no-unused-vars": [2, {
"varsIgnorePattern": "debug",
"argsIgnorePattern": "(err|settings|options)"
}],
"object-curly-spacing": [2, "never"],
"space-before-function-paren": [2, "never"],
"consistent-return": 0,
"arrow-body-style": 0,
"arrow-parens": ["error", "as-needed"],
"no-underscore-dangle": 0,
"global-require": 0,
"no-var": 0,
"no-continue": 0,
"prefer-const": 2,
"prefer-template": 0,
"no-param-reassign": 0,
"import/extensions": 0,
"import/newline-after-import": 0,
"import/no-extraneous-dependencies": [
"error",
{
"devDependencies": true,
"optionalDependencies": false,
"peerDependencies": false
}
]
},
"env": {
"node": true,
"mocha": true
}
}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
172 changes: 172 additions & 0 deletions bin/aero.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
#!/usr/bin/env node

require('any-promise/register/bluebird');

const program = require('commander');
const _ = require('lodash');
const updateNotifier = require('update-notifier');
const shortid = require('shortid');
const pkg = require('../package.json');
const winston = require('winston');
const cliInit = require('../lib/cli-init');

require('simple-errors');

winston.remove(winston.transports.Console);
winston.add(winston.transports.Console, {
timestamp: false,
colorize: true
});

const log = winston;

// Limit any generated IDs to alpha-numeric characters
shortid.characters(
'0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$-');

updateNotifier({
packageName: pkg.name,
packageVersion: pkg.version,
updateCheckInterval: 1000 * 60 * 60 * 2 // Check for updates every 2 hours
}).notify();

program.version(pkg.version)
.option('--debug', 'Emit debug messages')
.option('--customer [customerId]', 'The id of the Aerobatic customer account to perform the command on behalf of.')
// .option('--token [token]', 'JSON web token')
.option('--app-id [appId]', 'Set appId (in place of the one defined in package.json)');

// Create new application
program
.option('-n, --app-name [appName]', 'The unique name of the application')
.command('create')
.description('Create a new Aerobatic app from the current working directory')
.action(commandAction(require('../commands/create')));

// program
// .command('delete-app')
// .description('Delete an existing application')
// .action(commandAction('delete-app', {
// requireAuth: true,
// loadVirtualApp: true,
// loadManifest: false
// }));

// List the applications for an organization
program
.command('list')
.description('List the applications for customer account')
.action(commandAction(require('../commands/list')));

// Set an environment variable
// program
// .option('--key [key]')
// .option('--value [value]')
// .option('--virtual-env [virtualEnv]')
// .option('--encrypt')
// .command('set-env')
// .description('Set an environment variable')
// .action(commandAction('env', {
// requireAuth: true,
// loadManifest: true,
// loadVirtualApp: true,
// subCommand: 'set'
// }));

// List the environment variables
// program
// .command('list-env')
// .description('List the environment variables')
// .action(commandAction('env', {
// requireAuth: true,
// loadManifest: true,
// loadVirtualApp: true,
// subCommand: 'list'
// }));
//
// // Set an environment variable
// program
// .option('--key [key]')
// .option('--virtual-env [virtualEnv]')
// .command('delete-env')
// .description('Deletes an environment variable')
// .action(commandAction('env', {
// requireAuth: true,
// loadManifest: true,
// loadVirtualApp: true,
// subCommand: 'delete'
// }));

// Deploy app
// program
// .option('--version-name [versionName]', 'Version name')
// .option('-m, --message [message]', 'Version message')
// .option('-f, --force', 'Force all production traffic to the new version')
// .option('--open', 'Open the newly deployed version in a browser tab', true)
// .command('deploy')
// .description('Deploy a new version of the app')
// .action(commandAction('deploy', {
// requireAuth: true,
// loadVirtualApp: true,
// loadManifest: true
// }));

program
.option('-u --email [email]', 'Email username')
.command('login')
.description('Login to Aerobatic to generate a new JWT in the ~/.aerobatic.json file')
.action(commandAction(require('../commands/login'), {
requireAuth: false
}));

program.command('*')
.action(() => {
log.error('Invalid command ' + process.argv.slice(2));
});

program.parse(process.argv);

if (!process.argv.slice(2).length) {
program.outputHelp();
}

if (program.debug) {
winston.level = 'debug';
}

process.on('exit', () => {
log.debug('Exiting');
});

function commandAction(command, commandOptions) {
// debugger;
// Extend any options from program to options.
return () => {
_.defaults(program, {
cwd: process.cwd(),
customerId: process.env.AERO_CUSTOMER,
subCommand: (commandOptions || {}).subCommand
});

// Run the command
log.debug('Initialize the CLI');
cliInit(program, commandOptions)
.then(() => command(program))
.catch(err => {
if (err.status === 401) {
log.error('Invalid authToken. Try logging in first with `aero login`.');
} else {
const errMessage = err.message;

if (err.status === 500 && program.debug) {
var errorJson = _.omit(Error.toJson(err), 'message');
log.error(errMessage + ': %j', errorJson);
} else {
log.error(errMessage);
}
}

process.exit(1);
});
};
}
25 changes: 25 additions & 0 deletions commands/create.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
const log = require('winston');
const api = require('../lib/api');

// Command to create a new application
module.exports = program => {
log.debug('Create application %s', program.appName);
return api.post({
url: '/apps',
authToken: program.userConfig.auth,
body: {
name: program.appName,
customerId: program.customerId
}
})
.catch(error => {
switch (error.code) {
case 'invalidAppName':
throw new Error('App name is invalid. Must be url-friendly string consisting only of numbers, lowercase letters, and dashes.');
case 'appNameUnavailable':
throw new Error('The app name ' + program.appName + ' is not available. Please try a different name.');
default:
throw error;
}
});
};
Empty file added commands/deploy.js
Empty file.
32 changes: 32 additions & 0 deletions commands/list.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
const log = require('winston');
const _ = require('lodash');
const api = require('../lib/api');

// Command to create a new application
module.exports = program => {
var customerId = program.customerId;
if (!customerId && _.isObject(program.userConfig.customerRoles)) {
const customerIds = Object.keys(program.userConfig.customerRoles);
if (customerIds.length > 0) {
customerId = customerIds[0];
}
}

if (!customerId) {
throw new Error('No customerId context available. Run `aero accounts` to see a list of available accounts.');
}

log.debug('List applications for customer %s', customerId);
return api.get({
url: '/customers/' + customerId + '/apps',
authToken: program.userConfig.auth
})
.then(apps => {
apps.forEach(app => {
process.stdout.write(_.padEnd(app.name, 25, ' '));
process.stdout.write(_.padEnd(app.url, 40, ' '));
process.stdout.write(_.padEnd(app.paidPlan ? 'PROD' : 'DEV'));
process.stdout.write('\n');
});
});
};
41 changes: 41 additions & 0 deletions commands/login.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
const log = require('winston');
const inquirer = require('inquirer');
const userConfig = require('../lib/user-config');
const api = require('../lib/api');

module.exports = program => {
log.debug('Running the login command');

// Prompt for login
inquirer.prompt([
{
type: 'input',
name: 'email',
default: program.userConfig.email,
message: 'Email:'
}, {
type: 'password',
name: 'password',
message: 'Password:'
}
])
.then(answers => {
return api.post({
url: '/auth/login',
body: {email: answers.email, password: answers.password},
requireAuth: false
})
.then(result => {
return userConfig.set({
auth: result.idToken,
email: answers.email,
customerRoles: result.customerRoles
});
});
})
.then(config => {
program.userConfig = config;
log.info('Successfully logged in');
return null;
});
};
49 changes: 49 additions & 0 deletions lib/api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
const request = require('request-promise');
const urlJoin = require('url-join');
const _ = require('lodash');
const baseUrl = 'http://localhost:9000';

module.exports = {
get,
post,
// del,
// put
};

function makeRequest(method, options) {
if (_.isString(options)) {
options = {url: options};
} else {
options.url = urlJoin(baseUrl, options.url);
}

Object.assign(options, {
method,
json: true,
simple: false,
resolveWithFullResponse: true
});

if (options.authToken) {
options.headers = {
'X-Access-Token': options.authToken
};
}

return request(options)
.then(response => {
if (response.statusCode < 200 || response.statusCode >= 300) {
throw Error.http(response.statusCode,
response.body.message, _.omit(response.body, 'message'));
}
return response.body;
});
}

function get(options) {
return makeRequest('get', options);
}

function post(options) {
return makeRequest('post', options);
}
Loading

0 comments on commit 8e90f22

Please sign in to comment.