Skip to content

Commit b91252e

Browse files
committed
Merge branch 'develop', prepare 0.19.0
2 parents 91d1fe7 + 45e0027 commit b91252e

File tree

9 files changed

+467
-7
lines changed

9 files changed

+467
-7
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ To run Exoframe you need two parts - Exoframe CLI on your local machine and [Exo
2626

2727
## Installation and Usage
2828

29-
Install Exoframe CLI (needs at least Node 8.0):
29+
You can use one of the pre-packaged binaries from [releases](https://github.com/exoframejs/exoframe/releases).
30+
Or if you have Node installed, you can install Exoframe CLI using NPM (needs at least Node 8.0):
3031

3132
```
3233
npm install exoframe -g

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"package": "pkg --targets node8.3.0-linux-x64,node8.3.0-win-x64,node8.3.0-macos-x64 -o exoframe index.js"
1616
},
1717
"dependencies": {
18+
"boxen": "^1.2.1",
1819
"chalk": "^2.1.0",
1920
"cli-table": "^0.3.1",
2021
"got": "^7.1.0",
@@ -26,6 +27,7 @@
2627
"opn": "^5.1.0",
2728
"ora": "^1.3.0",
2829
"tar-fs": "^1.15.3",
30+
"update-notifier": "^2.2.0",
2931
"yargs": "^8.0.2"
3032
},
3133
"devDependencies": {

src/commands/update.js

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// npm packages
2+
const _ = require('lodash');
3+
const got = require('got');
4+
const chalk = require('chalk');
5+
6+
// our packages
7+
const {userConfig, isLoggedIn, logout} = require('../config');
8+
9+
// valid targets list
10+
const validTargets = ['traefik', 'server'];
11+
12+
exports.command = ['update [target]'];
13+
exports.describe = 'update given target';
14+
exports.builder = {
15+
target: {
16+
alias: 't',
17+
description: `Target for update (${validTargets.join(', ')})`,
18+
},
19+
};
20+
exports.handler = async ({target} = {target: 'self'}) => {
21+
if (!isLoggedIn()) {
22+
return;
23+
}
24+
25+
if (!validTargets.includes(target)) {
26+
console.log(
27+
chalk.red('Error!'),
28+
'Invalid target! Should be one of:',
29+
validTargets.map(it => chalk.green(it)).join(', ')
30+
);
31+
return;
32+
}
33+
34+
console.log(chalk.bold(`Updating ${target} on:`), userConfig.endpoint);
35+
36+
// services request url
37+
const remoteUrl = `${userConfig.endpoint}/update/${target}`;
38+
// construct shared request params
39+
const options = {
40+
headers: {
41+
Authorization: `Bearer ${userConfig.token}`,
42+
},
43+
json: true,
44+
};
45+
// try sending request
46+
try {
47+
const {body, statusCode} = await got.post(remoteUrl, options);
48+
if (statusCode !== 200 || body.error) {
49+
throw new Error(body.error || 'Oops. Something went wrong! Try again please.');
50+
}
51+
52+
if (body.updated) {
53+
console.log(chalk.green(`Successfully updated ${target}!`));
54+
return;
55+
}
56+
57+
console.log(chalk.green(`${_.capitalize(target)} is already up to date!`));
58+
} catch (e) {
59+
// if authorization is expired/broken/etc
60+
if (e.statusCode === 401) {
61+
logout(userConfig);
62+
console.log(chalk.red('Error: authorization expired!'), 'Please, relogin and try again.');
63+
return;
64+
}
65+
66+
const reason = e.response.body && e.response.body.error ? e.response.body.error : e.toString();
67+
console.log(chalk.red(`Error updating ${target}:`), reason);
68+
console.log('Update log:\n');
69+
(e.response.body.log || 'No log available')
70+
.split('\n')
71+
.map(l => {
72+
try {
73+
return JSON.parse(l);
74+
} catch (e) {
75+
return l;
76+
}
77+
})
78+
.filter(l => l !== undefined)
79+
.map(l => l.trim())
80+
.filter(l => l && l.length > 0)
81+
.forEach(line => console.log(line));
82+
}
83+
};

src/index.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
// npm packages
22
const yargs = require('yargs');
33

4+
// our packages
5+
const checkUpdate = require('./util/checkUpdate');
6+
47
// version
58
const pkg = require('../package.json');
69

10+
// check for updates on start
11+
checkUpdate(pkg);
12+
713
// our packages
814
const login = require('./commands/login');
915
const deploy = require('./commands/deploy');
@@ -13,6 +19,7 @@ const remove = require('./commands/remove');
1319
const endpoint = require('./commands/endpoint');
1420
const config = require('./commands/config');
1521
const token = require('./commands/token');
22+
const update = require('./commands/update');
1623

1724
// init program
1825
yargs
@@ -27,4 +34,5 @@ yargs
2734
.command(logs)
2835
.command(remove)
2936
.command(token)
30-
.command(config).argv;
37+
.command(config)
38+
.command(update).argv;

src/util/checkUpdate.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// npm packages
2+
const chalk = require('chalk');
3+
const boxen = require('boxen');
4+
const updateNotifier = require('update-notifier');
5+
6+
// boxen options
7+
const boxenOpts = {
8+
padding: 1,
9+
margin: 1,
10+
align: 'center',
11+
borderColor: 'yellow',
12+
borderStyle: 'round',
13+
};
14+
// packaged script path
15+
const pkgPath = '/snapshot/exoframe-cli/src/util';
16+
17+
// check function
18+
module.exports = pkg => {
19+
// Checks for available update and returns an instance
20+
const notifier = updateNotifier({
21+
pkg,
22+
updateCheckInterval: 1000,
23+
});
24+
// show message if update is available
25+
if (notifier.update) {
26+
const {update} = notifier;
27+
const isPackaged = __dirname === pkgPath;
28+
const upNpmMsg = `Run ${chalk.cyan('npm i -g exoframe')} to update`;
29+
const upPkgMsg = `Download from ${chalk.cyan('https://github.com/exoframejs/exoframe/releases')}`;
30+
const upmsg = isPackaged ? upPkgMsg : upNpmMsg;
31+
const message = `Update available ${chalk.dim(update.current)} ${chalk.reset(' → ')} ${chalk.green(
32+
update.latest
33+
)}\n${upmsg}`;
34+
console.log(`\n${boxen(message, boxenOpts)}`);
35+
}
36+
};

test/fixtures/cli.config.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
endpoint: 'http://localhost:8080'
2+
endpoints:
3+
- endpoint: 'http://test.endpoint'
4+
user: null
5+
token: null
26
token: test-token
37
user:
48
username: admin

test/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const list = require('./list');
77
const config = require('./config');
88
const token = require('./token');
99
const endpoint = require('./endpoint');
10+
const update = require('./update');
1011

1112
// run tests
1213
login();
@@ -17,3 +18,4 @@ list();
1718
config();
1819
token();
1920
endpoint();
21+
update();

test/update.js

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
// npm packages
2+
const tap = require('tap');
3+
const nock = require('nock');
4+
const sinon = require('sinon');
5+
6+
// our packages
7+
const {handler: update} = require('../src/commands/update');
8+
const {userConfig, updateConfig} = require('../src/config');
9+
10+
module.exports = () => {
11+
// test update
12+
tap.test('Should update traefik', t => {
13+
// handle correct request
14+
const updateServer = nock('http://localhost:8080')
15+
.post('/update/traefik')
16+
.reply(200, {updated: true});
17+
// spy on console
18+
const consoleSpy = sinon.spy(console, 'log');
19+
// execute login
20+
update({target: 'traefik'}).then(() => {
21+
// make sure log in was successful
22+
// check that server was called
23+
t.ok(updateServer.isDone());
24+
// first check console output
25+
t.deepEqual(
26+
consoleSpy.args,
27+
[['Updating traefik on:', 'http://localhost:8080'], ['Successfully updated traefik!']],
28+
'Correct log output'
29+
);
30+
// restore console
31+
console.log.restore();
32+
updateServer.done();
33+
t.end();
34+
});
35+
});
36+
37+
// test update
38+
tap.test('Should update server', t => {
39+
// handle correct request
40+
const updateServer = nock('http://localhost:8080')
41+
.post('/update/server')
42+
.reply(200, {updated: true});
43+
// spy on console
44+
const consoleSpy = sinon.spy(console, 'log');
45+
// execute login
46+
update({target: 'server'}).then(() => {
47+
// make sure log in was successful
48+
// check that server was called
49+
t.ok(updateServer.isDone());
50+
// first check console output
51+
t.deepEqual(
52+
consoleSpy.args,
53+
[['Updating server on:', 'http://localhost:8080'], ['Successfully updated server!']],
54+
'Correct log output'
55+
);
56+
// restore console
57+
console.log.restore();
58+
updateServer.done();
59+
t.end();
60+
});
61+
});
62+
63+
// test update error
64+
tap.test('Should display update error', t => {
65+
// handle correct request
66+
const response = {updated: false, error: 'Test error', log: 'log'};
67+
const updateServer = nock('http://localhost:8080')
68+
.post('/update/traefik')
69+
.reply(500, response);
70+
// spy on console
71+
const consoleSpy = sinon.spy(console, 'log');
72+
// execute login
73+
update({target: 'traefik'}).then(() => {
74+
// make sure log in was successful
75+
// check that server was called
76+
t.ok(updateServer.isDone());
77+
// first check console output
78+
t.deepEqual(
79+
consoleSpy.args,
80+
[
81+
['Updating traefik on:', 'http://localhost:8080'],
82+
['Error updating traefik:', 'Test error'],
83+
['Update log:\n'],
84+
['log'],
85+
],
86+
'Correct log output'
87+
);
88+
// restore console
89+
console.log.restore();
90+
updateServer.done();
91+
t.end();
92+
});
93+
});
94+
95+
// test deauth
96+
tap.test('Should deauth on 401', t => {
97+
// copy original config for restoration
98+
const originalConfig = Object.assign({}, userConfig);
99+
// handle correct request
100+
const updateServer = nock('http://localhost:8080')
101+
.post(`/update/traefik`)
102+
.reply(401);
103+
// spy on console
104+
const consoleSpy = sinon.spy(console, 'log');
105+
// execute login
106+
update({target: 'traefik'}).then(() => {
107+
// make sure log in was successful
108+
// check that server was called
109+
t.ok(updateServer.isDone());
110+
// first check console output
111+
t.deepEqual(
112+
consoleSpy.args,
113+
[
114+
['Updating traefik on:', 'http://localhost:8080'],
115+
['Error: authorization expired!', 'Please, relogin and try again.'],
116+
],
117+
'Correct log output'
118+
);
119+
// check config
120+
t.notOk(userConfig.user, 'Should not have user');
121+
t.notOk(userConfig.token, 'Should not have token');
122+
// restore console
123+
console.log.restore();
124+
// tear down nock
125+
updateServer.done();
126+
// restore original config
127+
updateConfig(originalConfig);
128+
t.end();
129+
});
130+
});
131+
};

0 commit comments

Comments
 (0)