Skip to content

Commit 1d42c69

Browse files
committed
Merge branch 'develop', prepare 5.1 release
2 parents d6e24d5 + 16f3e71 commit 1d42c69

File tree

18 files changed

+621
-182
lines changed

18 files changed

+621
-182
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,5 @@ exoframe-win.exe
88
.idea/
99
.DS_Store
1010

11+
package-lock.json
12+
exoframe.json

docs/Basics.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ All of the configuration for the deployed projects is done using `exoframe.json`
8686
It can either be generated/updated using `exoframe config` (or `exoframe init`) command or created manually.
8787
If it doesn't exist during deployment, Exoframe will generate simple config file that only contains name of the current project.
8888

89+
You can also tell Exoframe to use alternative config file during deployment by supplying `--config` (or `-c`) flag, e.g.: `exoframe -c exoframe.dev.json`
90+
8991
Config file has the following structure:
9092

9193
```js

package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "exoframe",
3-
"version": "5.0.0",
3+
"version": "5.0.2-dev",
44
"description": "Exoframe is a self-hosted tool that allows simple one-command deployments using Docker",
55
"main": "index.js",
66
"repository": "[email protected]:exoframejs/exoframe.git",
@@ -25,7 +25,7 @@
2525
"inquirer": "^6.5.0",
2626
"js-yaml": "^3.13.1",
2727
"jsonwebtoken": "^8.5.1",
28-
"lodash": "^4.17.14",
28+
"lodash": "^4.17.15",
2929
"multimatch": "^4.0.0",
3030
"open": "^6.4.0",
3131
"ora": "^3.4.0",
@@ -36,10 +36,10 @@
3636
"devDependencies": {
3737
"babel-eslint": "^10.0.2",
3838
"coveralls": "^3.0.5",
39-
"eslint": "^6.0.1",
39+
"eslint": "^6.1.0",
4040
"eslint-config-prettier": "^6.0.0",
4141
"eslint-config-standard": "^13.0.1",
42-
"eslint-plugin-import": "^2.18.0",
42+
"eslint-plugin-import": "^2.18.2",
4343
"eslint-plugin-node": "^9.1.0",
4444
"eslint-plugin-prettier": "^3.1.0",
4545
"eslint-plugin-promise": "^4.2.1",

src/commands/config.js

Lines changed: 147 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,10 @@ const volumeValidation = input => {
4444

4545
const writeConfig = (configPath, newConfig) => {
4646
// init config object
47-
const config = {name: newConfig.name, restart: newConfig.restart};
47+
const config = {name: newConfig.name};
48+
if (newConfig.restart && newConfig.restart.length) {
49+
config.restart = newConfig.restart;
50+
}
4851
if (newConfig.domain && newConfig.domain.length) {
4952
config.domain = newConfig.domain;
5053
}
@@ -116,59 +119,7 @@ const writeConfig = (configPath, newConfig) => {
116119
console.log(chalk.green('Config created!'));
117120
};
118121

119-
exports.command = ['config', 'init'];
120-
exports.describe = 'generate new config file for current project';
121-
exports.builder = {
122-
func: {
123-
alias: 'f',
124-
description: 'generate a new config for function deployment',
125-
},
126-
};
127-
exports.handler = async ({func} = {}) => {
128-
const workdir = process.cwd();
129-
const folderName = path.basename(workdir);
130-
const configPath = path.join(workdir, 'exoframe.json');
131-
let defaultConfig = {
132-
name: folderName,
133-
domain: '',
134-
project: '',
135-
restart: 'on-failure:2',
136-
env: undefined,
137-
labels: undefined,
138-
hostname: '',
139-
template: '',
140-
rateLimit: {
141-
period: '1s',
142-
average: 1,
143-
burst: 5,
144-
},
145-
basicAuth: false,
146-
function: false,
147-
};
148-
try {
149-
fs.statSync(configPath);
150-
console.log(chalk.green('Config already exists! Editing..'));
151-
defaultConfig = JSON.parse(fs.readFileSync(configPath).toString());
152-
} catch (e) {
153-
// check if config didn't exist
154-
if (e.message.includes('ENOENT')) {
155-
console.log('Creating new config..');
156-
} else {
157-
// if there was any parsing error - show message and die
158-
console.log(chalk.red('Error parsing existing config! Please make sure it is valid and try again.'));
159-
return;
160-
}
161-
}
162-
163-
if (func) {
164-
console.log('Creating new config for function deployment..');
165-
// set function flag to true
166-
defaultConfig.function = true;
167-
// write config to file
168-
writeConfig(configPath, defaultConfig);
169-
return;
170-
}
171-
122+
const generatePrompts = defaultConfig => {
172123
// ask user for values
173124
// generate and show choices
174125
const prompts = [];
@@ -180,19 +131,47 @@ exports.handler = async ({func} = {}) => {
180131
validate,
181132
filter,
182133
});
134+
135+
// function deployment part
136+
prompts.push({
137+
type: 'confirm',
138+
name: 'function',
139+
message: 'Deploy as function? [optional]:',
140+
default: Boolean(defaultConfig.function),
141+
});
142+
prompts.push({
143+
type: 'input',
144+
name: 'functionType',
145+
message: 'Function type [http, worker, trigger, custom]:',
146+
default: defaultConfig.function && defaultConfig.function.type ? defaultConfig.function.type : 'http',
147+
filter,
148+
when: answers => answers.function,
149+
});
150+
prompts.push({
151+
type: 'input',
152+
name: 'functionRoute',
153+
message: 'Function route [optional]:',
154+
default: defaultConfig.function && defaultConfig.function.route ? defaultConfig.function.route : '',
155+
filter,
156+
when: answers => answers.function,
157+
});
158+
159+
// default stuff
183160
prompts.push({
184161
type: 'input',
185162
name: 'domain',
186163
message: 'Domain [optional]:',
187164
default: defaultConfig.domain,
188165
filter,
166+
when: answers => !answers.function,
189167
});
190168
prompts.push({
191169
type: 'input',
192170
name: 'project',
193171
message: 'Project [optional]:',
194172
default: defaultConfig.project,
195173
filter,
174+
when: answers => !answers.function,
196175
});
197176
prompts.push({
198177
type: 'input',
@@ -205,6 +184,7 @@ exports.handler = async ({func} = {}) => {
205184
: '',
206185
filter,
207186
validate: pairValidation,
187+
when: answers => !answers.function,
208188
});
209189
prompts.push({
210190
type: 'input',
@@ -217,6 +197,7 @@ exports.handler = async ({func} = {}) => {
217197
: '',
218198
filter,
219199
validate: pairValidation,
200+
when: answers => !answers.function,
220201
});
221202
prompts.push({
222203
type: 'input',
@@ -225,12 +206,14 @@ exports.handler = async ({func} = {}) => {
225206
default: defaultConfig.volumes ? defaultConfig.volumes.join(', ') : '',
226207
filter,
227208
validate: volumeValidation,
209+
when: answers => !answers.function,
228210
});
229211
prompts.push({
230212
type: 'confirm',
231213
name: 'enableRatelimit',
232214
message: 'Enable rate-limit? [optional]',
233-
default: !!defaultConfig.rateLimit,
215+
default: defaultConfig.rateLimit && defaultConfig.rateLimit.enabled,
216+
when: answers => !answers.function,
234217
});
235218
prompts.push({
236219
type: 'input',
@@ -262,27 +245,31 @@ exports.handler = async ({func} = {}) => {
262245
message: 'Hostname [optional]:',
263246
default: defaultConfig.hostname,
264247
filter,
248+
when: answers => !answers.function,
265249
});
266250
prompts.push({
267251
type: 'list',
268252
name: 'restart',
269253
message: 'Restart policy [optional]:',
270254
default: defaultConfig.restart,
271-
choices: ['no', 'on-failure:2', 'always'],
255+
choices: ['', 'no', 'on-failure:2', 'always'],
256+
when: answers => !answers.function,
272257
});
273258
prompts.push({
274259
type: 'input',
275260
name: 'template',
276261
message: 'Template [optional]:',
277262
default: defaultConfig.template,
278263
filter,
264+
when: answers => !answers.function,
279265
});
280266
// docker image deployment part
281267
prompts.push({
282268
type: 'confirm',
283269
name: 'deployWithImage',
284270
message: 'Deploy using docker image? [optional]:',
285271
default: Boolean(defaultConfig.image),
272+
when: answers => !answers.function,
286273
});
287274
prompts.push({
288275
type: 'input',
@@ -301,36 +288,13 @@ exports.handler = async ({func} = {}) => {
301288
when: ({deployWithImage}) => deployWithImage,
302289
});
303290

304-
// function deployment part
305-
prompts.push({
306-
type: 'confirm',
307-
name: 'function',
308-
message: 'Deploy as function? [optional]:',
309-
default: Boolean(defaultConfig.function),
310-
});
311-
prompts.push({
312-
type: 'input',
313-
name: 'functionType',
314-
message: 'Function type [http, worker, trigger, custom]:',
315-
default: defaultConfig.function && defaultConfig.function.type ? defaultConfig.function.type : 'http',
316-
filter,
317-
when: answers => answers.function,
318-
});
319-
prompts.push({
320-
type: 'input',
321-
name: 'functionRoute',
322-
message: 'Function route [optional]:',
323-
default: defaultConfig.function && defaultConfig.function.route ? defaultConfig.function.route : '',
324-
filter,
325-
when: answers => answers.function,
326-
});
327-
328291
// basic auth part
329292
prompts.push({
330293
type: 'confirm',
331294
name: 'basicAuth',
332295
message: 'Add a basic auth user? [optional]:',
333296
default: Boolean(defaultConfig.basicAuth),
297+
when: answers => !answers.function,
334298
});
335299
// prompts for recursive questions
336300
const recursivePrompts = [];
@@ -365,12 +329,110 @@ exports.handler = async ({func} = {}) => {
365329
}
366330
};
367331

368-
// get values from user
369-
const newConfig = await inquirer.prompt(prompts);
332+
return {prompts, askForUsers};
333+
};
370334

371-
// update users for auth if needed
372-
if (newConfig.basicAuth) {
373-
newConfig.users = await askForUsers();
335+
exports.command = ['config', 'init'];
336+
exports.describe = 'generate new config file for current project';
337+
exports.builder = {
338+
func: {
339+
alias: 'f',
340+
description: 'generate a new config for function deployment',
341+
},
342+
domain: {
343+
alias: 'd',
344+
description: 'sets the domain (enables non-interactive mode)',
345+
},
346+
project: {
347+
alias: 'p',
348+
description: 'sets the project name (enables non-interactive mode)',
349+
},
350+
name: {
351+
alias: 'n',
352+
description: 'sets the name (enables non-interactive mode)',
353+
},
354+
restart: {
355+
alias: 'r',
356+
description: 'sets the restart option (enables non-interactive mode)',
357+
},
358+
hostname: {
359+
description: 'sets the hostname (enables non-interactive mode)',
360+
},
361+
};
362+
exports.handler = async ({_, $0, func, ...args} = {}) => {
363+
const workdir = process.cwd();
364+
const folderName = path.basename(workdir);
365+
const nonInteractive = Object.keys(args).some(key => args[key].length > 0);
366+
const configPath = path.join(workdir, 'exoframe.json');
367+
let defaultConfig = {
368+
name: folderName,
369+
domain: '',
370+
project: '',
371+
restart: '',
372+
env: undefined,
373+
labels: undefined,
374+
hostname: '',
375+
template: '',
376+
rateLimit: {
377+
enabled: false,
378+
period: '1s',
379+
average: 1,
380+
burst: 5,
381+
},
382+
basicAuth: false,
383+
function: false,
384+
};
385+
try {
386+
fs.statSync(configPath);
387+
console.log(chalk.green('Config already exists! Editing..'));
388+
defaultConfig = JSON.parse(fs.readFileSync(configPath).toString());
389+
} catch (e) {
390+
// check if config didn't exist
391+
if (e.message.includes('ENOENT')) {
392+
console.log('Creating new config..');
393+
} else {
394+
// if there was any parsing error - show message and die
395+
console.log(chalk.red('Error parsing existing config! Please make sure it is valid and try again.'));
396+
return;
397+
}
398+
}
399+
400+
if (func) {
401+
console.log('Creating new config for function deployment..');
402+
// set function flag to true
403+
defaultConfig.function = true;
404+
// write config to file
405+
writeConfig(configPath, defaultConfig);
406+
return;
407+
}
408+
409+
let newConfig = defaultConfig;
410+
411+
if (nonInteractive) {
412+
console.log(chalk.yellow('Mode changed to'), 'non-interactive');
413+
}
414+
415+
const overrideFromArgument = (key, value) => {
416+
if (!value) return;
417+
console.log('Setting', chalk.red(key), 'to', chalk.yellow(value));
418+
newConfig[key] = value;
419+
};
420+
421+
overrideFromArgument('domain', args.domain);
422+
overrideFromArgument('name', args.name);
423+
overrideFromArgument('project', args.project);
424+
overrideFromArgument('restart', args.restart);
425+
overrideFromArgument('hostname', args.hostname);
426+
427+
if (!nonInteractive) {
428+
const {prompts, askForUsers} = generatePrompts(defaultConfig);
429+
// get values from user
430+
newConfig = await inquirer.prompt(prompts);
431+
432+
// update users for auth if needed
433+
if (newConfig.basicAuth) {
434+
newConfig.users = await askForUsers();
435+
}
374436
}
375437

376438
writeConfig(configPath, {...defaultConfig, ...newConfig});

0 commit comments

Comments
 (0)