Skip to content

Commit

Permalink
Merge pull request #1363 from ParsePlatform/issue/1319
Browse files Browse the repository at this point in the history
Improves config loading and tests
  • Loading branch information
gfosco committed Apr 5, 2016
2 parents 27dd2eb + 8c92b80 commit 7e52c18
Show file tree
Hide file tree
Showing 8 changed files with 155 additions and 39 deletions.
68 changes: 60 additions & 8 deletions spec/CLI.spec.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use strict';
var commander = require("../src/cli/utils/commander").default;

var definitions = {
Expand All @@ -11,7 +12,7 @@ var definitions = {
action: function(value) {
var value = parseInt(value);
if (!Number.isInteger(value)) {
throw "port is invalid";
throw "arg2 is invalid";
}
return value;
}
Expand All @@ -23,7 +24,7 @@ var definitions = {
}

describe("commander additions", () => {

afterEach((done) => {
commander.options = [];
delete commander.arg0;
Expand All @@ -33,7 +34,7 @@ describe("commander additions", () => {
delete commander.arg4;
done();
})

it("should load properly definitions from args", (done) => {
commander.loadDefinitions(definitions);
commander.parse(["node","./CLI.spec.js","--arg0", "arg0Value", "--arg1", "arg1Value", "--arg2", "2", "--arg3", "some"]);
Expand All @@ -44,7 +45,7 @@ describe("commander additions", () => {
expect(commander.arg4).toEqual("arg4Value");
done();
});

it("should load properly definitions from env", (done) => {
commander.loadDefinitions(definitions);
commander.parse([], {
Expand All @@ -58,7 +59,7 @@ describe("commander additions", () => {
expect(commander.arg4).toEqual("arg4Value");
done();
});

it("should load properly use args over env", (done) => {
commander.loadDefinitions(definitions);
commander.parse(["node","./CLI.spec.js","--arg0", "arg0Value", "--arg4", "anotherArg4"], {
Expand All @@ -72,7 +73,7 @@ describe("commander additions", () => {
expect(commander.arg4).toEqual("anotherArg4");
done();
});

it("should fail in action as port is invalid", (done) => {
commander.loadDefinitions(definitions);
expect(()=> {
Expand All @@ -81,7 +82,58 @@ describe("commander additions", () => {
"PROGRAM_ARG_1": "arg1ENVValue",
"PROGRAM_ARG_2": "hello",
});
}).toThrow("port is invalid");
}).toThrow("arg2 is invalid");
done();
});

it("should not override config.json", (done) => {
commander.loadDefinitions(definitions);
commander.parse(["node","./CLI.spec.js","--arg0", "arg0Value", "./spec/configs/CLIConfig.json"], {
"PROGRAM_ARG_0": "arg0ENVValue",
"PROGRAM_ARG_1": "arg1ENVValue",
});
let options = commander.getOptions();
expect(options.arg2).toBe(8888);
expect(options.arg3).toBe("hello"); //config value
expect(options.arg4).toBe('/1');
done();
});

it("should fail with invalid values in JSON", (done) => {
commander.loadDefinitions(definitions);
expect(() => {
commander.parse(["node","./CLI.spec.js","--arg0", "arg0Value", "./spec/configs/CLIConfigFail.json"], {
"PROGRAM_ARG_0": "arg0ENVValue",
"PROGRAM_ARG_1": "arg1ENVValue",
});
}).toThrow("arg2 is invalid")
done();
});

it("should fail when too many apps are set", (done) => {
commander.loadDefinitions(definitions);
expect(() => {
commander.parse(["node","./CLI.spec.js","./spec/configs/CLIConfigFailTooManyApps.json"]);
}).toThrow("Multiple apps are not supported")
done();
});

it("should load config from apps", (done) => {
commander.loadDefinitions(definitions);
commander.parse(["node", "./CLI.spec.js", "./spec/configs/CLIConfigApps.json"]);
let options = commander.getOptions();
expect(options.arg1).toBe("my_app");
expect(options.arg2).toBe(8888);
expect(options.arg3).toBe("hello"); //config value
expect(options.arg4).toBe('/1');
done();
});

it("should fail when passing an invalid arguement", (done) => {
commander.loadDefinitions(definitions);
expect(() => {
commander.parse(["node", "./CLI.spec.js", "./spec/configs/CLIConfigUnknownArg.json"]);
}).toThrow('error: unknown option myArg')
done();
});
});
});
6 changes: 6 additions & 0 deletions spec/configs/CLIConfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"arg1": "my_app",
"arg2": "8888",
"arg3": "hello",
"arg4": "/1"
}
9 changes: 9 additions & 0 deletions spec/configs/CLIConfigApps.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"apps": [
{
"arg1": "my_app",
"arg2": 8888,
"arg3": "hello",
"arg4": "/1"
}]
}
6 changes: 6 additions & 0 deletions spec/configs/CLIConfigFail.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"arg1": "my_app",
"arg2": "hello",
"arg3": "hello",
"arg4": "/1"
}
16 changes: 16 additions & 0 deletions spec/configs/CLIConfigFailTooManyApps.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"apps": [
{
"arg1": "my_app",
"arg2": "99999",
"arg3": "hello",
"arg4": "/1"
},
{
"arg1": "my_app2",
"arg2": "9999",
"arg3": "hello",
"arg4": "/1"
}
]
}
6 changes: 6 additions & 0 deletions spec/configs/CLIConfigUnknownArg.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"arg1": "my_app",
"arg2": "8888",
"arg3": "hello",
"myArg": "/1"
}
24 changes: 2 additions & 22 deletions src/cli/parse-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import express from 'express';
import { ParseServer } from '../index';
import definitions from './cli-definitions';
import program from './utils/commander';
import { mergeWithOptions } from './utils/commander';
import colors from 'colors';

program.loadDefinitions(definitions);
Expand Down Expand Up @@ -34,28 +35,7 @@ program.on('--help', function(){

program.parse(process.argv, process.env);

let options = {};
if (program.args.length > 0 ) {
let jsonPath = program.args[0];
jsonPath = path.resolve(jsonPath);
let jsonConfig = require(jsonPath);
if (jsonConfig.apps) {
if (jsonConfig.apps.length > 1) {
throw 'Multiple apps are not supported';
}
options = jsonConfig.apps[0];
} else {
options = jsonConfig;
}
console.log(`Configuation loaded from ${jsonPath}`)
}

options = Object.keys(definitions).reduce(function (options, key) {
if (typeof program[key] !== 'undefined') {
options[key] = program[key];
}
return options;
}, options);
let options = program.getOptions();

if (!options.serverURL) {
options.serverURL = `http://localhost:${options.port}${options.mountPath}`;
Expand Down
59 changes: 50 additions & 9 deletions src/cli/utils/commander.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Command } from 'commander';

import path from 'path';
let _definitions;
let _reverseDefinitions;
let _defaults;

Command.prototype.loadDefinitions = function(definitions) {
_definitions = definitions;

Object.keys(definitions).reduce((program, opt) => {
if (typeof definitions[opt] == "object") {
const additionalOptions = definitions[opt];
Expand All @@ -18,14 +18,14 @@ Command.prototype.loadDefinitions = function(definitions) {
}
return program.option(`--${opt} [${opt}]`);
}, this);

_defaults = Object.keys(definitions).reduce((defs, opt) => {
if(_definitions[opt].default) {
defs[opt] = _definitions[opt].default;
}
return defs;
}, {});

_reverseDefinitions = Object.keys(definitions).reduce((object, key) => {
let value = definitions[key];
if (typeof value == "object") {
Expand All @@ -36,7 +36,7 @@ Command.prototype.loadDefinitions = function(definitions) {
}
return object;
}, {});

/* istanbul ignore next */
this.on('--help', function(){
console.log(' Configure From Environment:');
Expand All @@ -58,28 +58,69 @@ function parseEnvironment(env = {}) {
}
options[_reverseDefinitions[key]] = action(env[key]);
}
return options;
return options;
}, {});
}

function parseConfigFile(program) {
let options = {};
if (program.args.length > 0) {
let jsonPath = program.args[0];
jsonPath = path.resolve(jsonPath);
let jsonConfig = require(jsonPath);
if (jsonConfig.apps) {
if (jsonConfig.apps.length > 1) {
throw 'Multiple apps are not supported';
}
options = jsonConfig.apps[0];
} else {
options = jsonConfig;
}
Object.keys(options).forEach((key) => {
let value = options[key];
if (!_definitions[key]) {
throw `error: unknown option ${key}`;
}
let action = _definitions[key].action;
if (action) {
options[key] = action(value);
}
})
console.log(`Configuation loaded from ${jsonPath}`)
}
return options;
}

Command.prototype.setValuesIfNeeded = function(options) {
Object.keys(options).forEach((key) => {
if (!this[key]) {
this[key] = options[key];
}
}
});
}
}

Command.prototype._parse = Command.prototype.parse;

Command.prototype.parse = function(args, env) {
this._parse(args);
// Parse the environment first
const envOptions = parseEnvironment(env);

const fromFile = parseConfigFile(this);
// Load the env if not passed from command line
this.setValuesIfNeeded(envOptions);
// Load from file to override
this.setValuesIfNeeded(fromFile);
// Last set the defaults
this.setValuesIfNeeded(_defaults);
}

Command.prototype.getOptions = function() {
return Object.keys(_definitions).reduce((options, key) => {
if (typeof this[key] !== 'undefined') {
options[key] = this[key];
}
return options;
}, {});
}

export default new Command();

0 comments on commit 7e52c18

Please sign in to comment.