Skip to content

Commit 98bdba2

Browse files
committed
Merge branch 'develop', prepare 0.20.0
2 parents 47dc602 + b4f97eb commit 98bdba2

File tree

6 files changed

+347
-12
lines changed

6 files changed

+347
-12
lines changed

src/commands/endpoint-rm.js

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// npm packages
2+
const chalk = require('chalk');
3+
const inquirer = require('inquirer');
4+
5+
// our packages
6+
const {userConfig, updateConfig} = require('../config');
7+
8+
exports.command = 'rm-endpoint [url]';
9+
exports.describe = 'remove existing exoframe endpoint';
10+
exports.builder = {
11+
url: {
12+
alias: 'u',
13+
default: '',
14+
description: 'URL of an existing endpoint',
15+
},
16+
};
17+
exports.handler = async ({url}) => {
18+
let endpointUrl = url;
19+
20+
// if one endpoint only - show error
21+
if (!userConfig.endpoints || !userConfig.endpoints.length) {
22+
console.log(chalk.red('Error!'), chalk.bold('Cannot remove the only endpoint URL:'), userConfig.endpoint);
23+
return;
24+
}
25+
26+
// if not endpoint url given - show selector
27+
if (!endpointUrl || !endpointUrl.length) {
28+
// if multiple - show selector
29+
const prompts = [];
30+
prompts.push({
31+
type: 'list',
32+
name: 'delEndpoint',
33+
message: 'Choose endpoint to remove:',
34+
default: userConfig.endpoint,
35+
choices: [userConfig.endpoint].concat(userConfig.endpoints.map(entry => entry.endpoint)),
36+
});
37+
const {delEndpoint} = await inquirer.prompt(prompts);
38+
// assign new selected as entered endpoint
39+
endpointUrl = delEndpoint;
40+
}
41+
42+
// if current endpoint set - move it to endpoints
43+
if (userConfig.endpoint === endpointUrl) {
44+
console.log(chalk.bold('Removing endpoint:'), endpointUrl);
45+
const newData = userConfig.endpoints.shift();
46+
const endpoint = newData.endpoint;
47+
const user = newData ? newData.user : null;
48+
const token = newData ? newData.token : null;
49+
const endpoints = userConfig.endpoints.filter(e => e.endpoint !== newData.endpoint);
50+
updateConfig({endpoint, user, token, endpoints});
51+
console.log(chalk.green('Endpoint removed!'));
52+
return;
53+
}
54+
55+
const index = userConfig.endpoints.findIndex(it => it.endpoint === endpointUrl);
56+
if (index === -1) {
57+
console.log(chalk.red('Error!'), "Couldn't find endpoint with URL:", endpointUrl);
58+
return;
59+
}
60+
61+
// then write new endpoint to current one and remove user/token
62+
console.log(chalk.bold('Removing endpoint:'), endpointUrl);
63+
const endpoints = userConfig.endpoints.filter(e => e.endpoint !== endpointUrl);
64+
updateConfig({endpoints});
65+
console.log(chalk.green('Endpoint removed!'));
66+
};

src/commands/update.js

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
const _ = require('lodash');
33
const got = require('got');
44
const chalk = require('chalk');
5+
const ora = require('ora');
56

67
// our packages
78
const {userConfig, isLoggedIn, logout} = require('../config');
@@ -10,18 +11,58 @@ const {userConfig, isLoggedIn, logout} = require('../config');
1011
const validTargets = ['traefik', 'server'];
1112

1213
exports.command = ['update [target]'];
13-
exports.describe = 'update given target';
14+
exports.describe = 'check for updates or update given target';
1415
exports.builder = {
1516
target: {
1617
alias: 't',
1718
description: `Target for update (${validTargets.join(', ')})`,
1819
},
1920
};
20-
exports.handler = async ({target} = {target: 'self'}) => {
21+
exports.handler = async ({target}) => {
2122
if (!isLoggedIn()) {
2223
return;
2324
}
2425

26+
// construct shared request params
27+
const options = {
28+
headers: {
29+
Authorization: `Bearer ${userConfig.token}`,
30+
},
31+
json: true,
32+
};
33+
34+
// if no target given - check for update
35+
if (!target || !target.length) {
36+
// show loader
37+
const spinner = ora('Checking for update...').start();
38+
39+
// services request url
40+
const remoteUrl = `${userConfig.endpoint}/version`;
41+
// send request
42+
const {body, statusCode} = await got.get(remoteUrl, options);
43+
if (statusCode !== 200 || body.error) {
44+
spinner.fail('Error checking for update');
45+
console.log(body.error || 'Oops. Something went wrong! Try again please.');
46+
return;
47+
}
48+
49+
if (body.serverUpdate || body.traefikUpdate) {
50+
spinner.warn('Updates available!');
51+
} else {
52+
spinner.succeed('You are up to date!');
53+
}
54+
55+
console.log();
56+
console.log(chalk.bold('Exoframe Server:'));
57+
console.log(` current: ${body.server}`);
58+
console.log(` latest: ${body.latestServer}`);
59+
console.log();
60+
console.log(chalk.bold('Traefik:'));
61+
console.log(` current: ${body.traefik}`);
62+
console.log(` latest: ${body.latestTraefik}`);
63+
return;
64+
}
65+
2566
if (!validTargets.includes(target)) {
2667
console.log(
2768
chalk.red('Error!'),
@@ -35,13 +76,6 @@ exports.handler = async ({target} = {target: 'self'}) => {
3576

3677
// services request url
3778
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-
};
4579
// try sending request
4680
try {
4781
const {body, statusCode} = await got.post(remoteUrl, options);

src/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ const list = require('./commands/list');
1717
const logs = require('./commands/logs');
1818
const remove = require('./commands/remove');
1919
const endpoint = require('./commands/endpoint');
20+
const endpointRm = require('./commands/endpoint-rm');
2021
const config = require('./commands/config');
2122
const token = require('./commands/token');
2223
const update = require('./commands/update');
@@ -30,6 +31,7 @@ yargs
3031
.command(deploy)
3132
.command(login)
3233
.command(endpoint)
34+
.command(endpointRm)
3335
.command(list)
3436
.command(logs)
3537
.command(remove)

test/endpoint.js

Lines changed: 176 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@ const inquirer = require('inquirer');
88

99
// our packages
1010
const {handler: updateEndpoint} = require('../src/commands/endpoint');
11+
const {handler: removeEndpoint} = require('../src/commands/endpoint-rm');
1112

1213
module.exports = () => {
1314
const configPath = path.join(__dirname, 'fixtures', 'cli.config.yml');
1415
const mockEndpoint = 'http://test.endpoint';
16+
const mockEndpoint2 = 'http://test';
1517

1618
// load original config
1719
const origCfg = yaml.safeLoad(fs.readFileSync(configPath, 'utf8'));
@@ -43,6 +45,36 @@ module.exports = () => {
4345
});
4446
});
4547

48+
// test config generation
49+
tap.test('Should add second new endpoint', t => {
50+
// spy on console
51+
const consoleSpy = sinon.spy(console, 'log');
52+
// execute login
53+
updateEndpoint({url: mockEndpoint2}).then(() => {
54+
// first check console output
55+
t.deepEqual(
56+
consoleSpy.args,
57+
[['Updating endpoint URL to:', mockEndpoint2], ['Endpoint URL updated!']],
58+
'Correct log output'
59+
);
60+
// then check config changes
61+
const cfg = yaml.safeLoad(fs.readFileSync(configPath, 'utf8'));
62+
t.equal(cfg.endpoint, mockEndpoint2, 'Correct endpoint');
63+
t.equal(cfg.user, null, 'Correct new user');
64+
t.equal(cfg.token, null, 'Correct token');
65+
t.equal(cfg.endpoints.length, 2, 'Correct new endpoints list');
66+
t.equal(cfg.endpoints[0].endpoint, origCfg.endpoint, 'Correct endpoint in list');
67+
t.equal(cfg.endpoints[0].user.username, origCfg.user.username, 'Correct user in list');
68+
t.equal(cfg.endpoints[0].token, origCfg.token, 'Correct token in list');
69+
t.equal(cfg.endpoints[1].endpoint, mockEndpoint, 'Correct endpoint in list');
70+
t.notOk(cfg.endpoints[1].user, 'Correct user in list');
71+
t.notOk(cfg.endpoints[1].token, 'Correct token in list');
72+
// restore console
73+
console.log.restore();
74+
t.end();
75+
});
76+
});
77+
4678
// test config generation
4779
tap.test('Should select old endpoint', t => {
4880
// spy on console
@@ -62,17 +94,158 @@ module.exports = () => {
6294
t.equal(cfg.endpoint, origCfg.endpoint, 'Correct endpoint');
6395
t.equal(cfg.user.username, origCfg.user.username, 'Correct new user');
6496
t.equal(cfg.token, origCfg.token, 'Correct token');
65-
t.equal(cfg.endpoints.length, 1, 'Correct new endpoints list');
97+
t.equal(cfg.endpoints.length, 2, 'Correct new endpoints list');
6698
t.equal(cfg.endpoints[0].endpoint, mockEndpoint, 'Correct endpoint in list');
6799
t.notOk(cfg.endpoints[0].user, 'Correct user in list');
68100
t.notOk(cfg.endpoints[0].token, 'Correct token in list');
101+
t.equal(cfg.endpoints[1].endpoint, mockEndpoint2, 'Correct endpoint in list');
102+
t.notOk(cfg.endpoints[1].user, 'Correct user in list');
103+
t.notOk(cfg.endpoints[1].token, 'Correct token in list');
104+
// restore console
105+
console.log.restore();
106+
// restore inquirer
107+
inquirer.prompt.restore();
108+
t.end();
109+
});
110+
});
111+
112+
// test config generation
113+
tap.test('Should select old endpoint using URL param', t => {
114+
// spy on console
115+
const consoleSpy = sinon.spy(console, 'log');
116+
// execute login
117+
updateEndpoint({url: mockEndpoint}).then(() => {
118+
// first check console output
119+
t.deepEqual(
120+
consoleSpy.args,
121+
[['Updating endpoint URL to:', mockEndpoint], ['Endpoint URL updated!']],
122+
'Correct log output'
123+
);
124+
// then check config changes
125+
const cfg = yaml.safeLoad(fs.readFileSync(configPath, 'utf8'));
126+
t.equal(cfg.endpoint, mockEndpoint, 'Correct endpoint');
127+
t.notOk(cfg.user, 'Correct new user');
128+
t.notOk(cfg.token, 'Correct token');
129+
t.equal(cfg.endpoints.length, 2, 'Correct new endpoints list');
130+
t.equal(cfg.endpoints[0].endpoint, mockEndpoint2, 'Correct endpoint in list');
131+
t.notOk(cfg.endpoints[0].user, 'Correct user in list');
132+
t.notOk(cfg.endpoints[0].token, 'Correct token in list');
133+
t.equal(cfg.endpoints[1].endpoint, origCfg.endpoint, 'Correct endpoint in list');
134+
t.equal(cfg.endpoints[1].user.username, origCfg.user.username, 'Correct user in list');
135+
t.equal(cfg.endpoints[1].token, origCfg.token, 'Correct token in list');
136+
// restore console
137+
console.log.restore();
138+
t.end();
139+
});
140+
});
141+
142+
tap.test('Should show error on remove of non-existent endpoint', t => {
143+
// spy on console
144+
const consoleSpy = sinon.spy(console, 'log');
145+
// stup inquirer answers
146+
sinon.stub(inquirer, 'prompt').callsFake(() => Promise.resolve({delEndpoint: 'do-not-exist'}));
147+
// execute login
148+
removeEndpoint({}).then(() => {
149+
// first check console output
150+
t.deepEqual(
151+
consoleSpy.args,
152+
[['Error!', "Couldn't find endpoint with URL:", 'do-not-exist']],
153+
'Correct log output'
154+
);
155+
// restore console
156+
console.log.restore();
157+
// restore inquirer
158+
inquirer.prompt.restore();
159+
t.end();
160+
});
161+
});
162+
163+
tap.test('Should remove current endpoint using inquirer', t => {
164+
// spy on console
165+
const consoleSpy = sinon.spy(console, 'log');
166+
// stup inquirer answers
167+
sinon.stub(inquirer, 'prompt').callsFake(() => Promise.resolve({delEndpoint: mockEndpoint}));
168+
// execute login
169+
removeEndpoint({}).then(() => {
170+
// first check console output
171+
t.deepEqual(consoleSpy.args, [['Removing endpoint:', mockEndpoint], ['Endpoint removed!']], 'Correct log output');
172+
// then check config changes
173+
const cfg = yaml.safeLoad(fs.readFileSync(configPath, 'utf8'));
174+
t.equal(cfg.endpoint, mockEndpoint2, 'Correct endpoint');
175+
t.notOk(cfg.user, 'Correct new user');
176+
t.notOk(cfg.token, 'Correct token');
177+
t.equal(cfg.endpoints.length, 1, 'Correct new endpoints list');
178+
t.equal(cfg.endpoints[0].endpoint, origCfg.endpoint, 'Correct endpoint in list');
179+
t.equal(cfg.endpoints[0].user.username, origCfg.user.username, 'Correct user in list');
180+
t.equal(cfg.endpoints[0].token, origCfg.token, 'Correct token in list');
69181
// restore console
70182
console.log.restore();
71183
// restore inquirer
72184
inquirer.prompt.restore();
73-
// restore original config
74-
fs.writeFileSync(configPath, yaml.safeDump(origCfg), 'utf8');
75185
t.end();
76186
});
77187
});
188+
189+
tap.test('Should remove existing endpoint using param', t => {
190+
let consoleSpy;
191+
// select original endpoint to test removal from list
192+
updateEndpoint({url: origCfg.endpoint})
193+
.then(() => {
194+
// spy on console
195+
consoleSpy = sinon.spy(console, 'log');
196+
// execute login
197+
return removeEndpoint({url: mockEndpoint2});
198+
})
199+
.then(() => {
200+
// first check console output
201+
t.deepEqual(
202+
consoleSpy.args,
203+
[['Removing endpoint:', mockEndpoint2], ['Endpoint removed!']],
204+
'Correct log output'
205+
);
206+
// then check config changes
207+
const cfg = yaml.safeLoad(fs.readFileSync(configPath, 'utf8'));
208+
console.log(cfg);
209+
t.equal(cfg.endpoint, origCfg.endpoint, 'Correct endpoint');
210+
t.equal(cfg.user.username, origCfg.user.username, 'Correct new user');
211+
t.equal(cfg.token, origCfg.token, 'Correct token');
212+
t.equal(cfg.endpoints.length, 0, 'Correct new endpoints list');
213+
// restore console
214+
console.log.restore();
215+
t.end();
216+
});
217+
});
218+
219+
tap.test('Should not remove only endpoint', t => {
220+
// spy on console
221+
const consoleSpy = sinon.spy(console, 'log');
222+
// stup inquirer answers
223+
sinon.stub(inquirer, 'prompt').callsFake(() => Promise.resolve({delEndpoint: origCfg.endpoint}));
224+
// execute login
225+
removeEndpoint({}).then(() => {
226+
// first check console output
227+
t.deepEqual(
228+
consoleSpy.args,
229+
[['Error!', 'Cannot remove the only endpoint URL:', origCfg.endpoint]],
230+
'Correct log output'
231+
);
232+
// then check config changes
233+
const cfg = yaml.safeLoad(fs.readFileSync(configPath, 'utf8'));
234+
t.equal(cfg.endpoint, origCfg.endpoint, 'Correct endpoint');
235+
t.equal(cfg.user.username, origCfg.user.username, 'Correct new user');
236+
t.equal(cfg.token, origCfg.token, 'Correct token');
237+
t.equal(cfg.endpoints.length, 0, 'Correct new endpoints list');
238+
// restore console
239+
console.log.restore();
240+
// restore inquirer
241+
inquirer.prompt.restore();
242+
t.end();
243+
});
244+
});
245+
246+
tap.test('Restore original config', t => {
247+
// restore original config
248+
fs.writeFileSync(configPath, yaml.safeDump(origCfg), 'utf8');
249+
t.end();
250+
});
78251
};

0 commit comments

Comments
 (0)