navy 6.0.0 → 7.0.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/__tests__/config-provider.js +75 -0
- package/lib/__tests__/config.js +130 -0
- package/lib/__tests__/driver-logging.js +148 -0
- package/lib/__tests__/driver.js +19 -0
- package/lib/__tests__/errors.js +49 -0
- package/lib/__tests__/http-proxy.js +214 -0
- package/lib/__tests__/index.js +25 -0
- package/lib/__tests__/service.js +16 -0
- package/lib/cli/__tests__/develop.js +239 -0
- package/lib/cli/__tests__/external-ip.js +68 -0
- package/lib/cli/__tests__/health.js +257 -0
- package/lib/cli/__tests__/https.js +210 -0
- package/lib/cli/__tests__/import.js +110 -0
- package/lib/cli/__tests__/index.js +118 -0
- package/lib/cli/__tests__/lan-ip.js +90 -0
- package/lib/cli/__tests__/launch.js +179 -0
- package/lib/cli/__tests__/live.js +155 -0
- package/lib/cli/__tests__/local-ip.js +72 -0
- package/lib/cli/__tests__/logs.js +52 -0
- package/lib/cli/__tests__/open.js +65 -0
- package/lib/cli/__tests__/program.js +472 -0
- package/lib/cli/__tests__/ps.js +345 -0
- package/lib/cli/__tests__/refresh-config.js +95 -0
- package/lib/cli/__tests__/run.js +54 -0
- package/lib/cli/__tests__/status.js +204 -0
- package/lib/cli/__tests__/updates.js +243 -0
- package/lib/cli/__tests__/wait-for-healthy.js +134 -0
- package/lib/cli/config/__tests__/index.js +275 -0
- package/lib/cli/config/__tests__/wrapper.js +53 -0
- package/lib/cli/config/index.js +19 -37
- package/lib/cli/config/wrapper.js +0 -6
- package/lib/cli/develop.js +7 -21
- package/lib/cli/doctor/__tests__/clean-compose-files.js +78 -0
- package/lib/cli/doctor/__tests__/index.js +67 -0
- package/lib/cli/doctor/__tests__/invalid-compose-config.js +103 -0
- package/lib/cli/doctor/__tests__/invalid-state.js +83 -0
- package/lib/cli/doctor/__tests__/util.js +91 -0
- package/lib/cli/doctor/clean-compose-files.js +5 -13
- package/lib/cli/doctor/index.js +0 -12
- package/lib/cli/doctor/invalid-compose-config.js +0 -4
- package/lib/cli/doctor/invalid-state.js +0 -6
- package/lib/cli/doctor/util.js +0 -10
- package/lib/cli/external-ip.js +0 -4
- package/lib/cli/health.js +0 -12
- package/lib/cli/https.js +9 -25
- package/lib/cli/import.js +0 -12
- package/lib/cli/index.js +0 -9
- package/lib/cli/lan-ip.js +2 -8
- package/lib/cli/launch.js +0 -9
- package/lib/cli/live.js +6 -16
- package/lib/cli/local-ip.js +2 -7
- package/lib/cli/logs.js +0 -3
- package/lib/cli/open.js +2 -7
- package/lib/cli/program.js +73 -101
- package/lib/cli/ps.js +1 -21
- package/lib/cli/refresh-config.js +0 -7
- package/lib/cli/run.js +0 -3
- package/lib/cli/status.js +0 -11
- package/lib/cli/updates.js +0 -22
- package/lib/cli/util/__tests__/get-or-initialise-navy.js +66 -0
- package/lib/cli/util/__tests__/import.js +123 -0
- package/lib/cli/util/__tests__/index.js +17 -0
- package/lib/cli/util/__tests__/merge-action-options.js +47 -0
- package/lib/cli/util/__tests__/reconfigure.js +78 -0
- package/lib/cli/util/get-or-initialise-navy.js +0 -7
- package/lib/cli/util/import.js +0 -9
- package/lib/cli/util/index.js +0 -2
- package/lib/cli/util/merge-action-options.js +20 -0
- package/lib/cli/util/reconfigure.js +0 -4
- package/lib/cli/wait-for-healthy.js +0 -21
- package/lib/client/registry/__tests__/get-credentials.js +62 -0
- package/lib/client/registry/__tests__/get-endpoint.js +124 -0
- package/lib/client/registry/__tests__/get-fat-manifest.js +67 -0
- package/lib/client/registry/__tests__/get-token.js +66 -0
- package/lib/client/registry/__tests__/helpers.js +26 -0
- package/lib/client/registry/get-credentials.js +3 -9
- package/lib/client/registry/get-endpoint.js +29 -63
- package/lib/client/registry/get-fat-manifest.js +2 -9
- package/lib/client/registry/get-token.js +2 -13
- package/lib/client/registry/helpers.js +0 -4
- package/lib/config-provider.js +0 -12
- package/lib/config-providers/filesystem/__tests__/index.js +176 -0
- package/lib/config-providers/filesystem/index.js +5 -23
- package/lib/config-providers/npm/__tests__/index.js +226 -0
- package/lib/config-providers/npm/__tests__/util.js +1 -2
- package/lib/config-providers/npm/index.js +12 -35
- package/lib/config-providers/npm/util.js +0 -3
- package/lib/config.js +4 -19
- package/lib/domain/__tests__/container-image.js +81 -0
- package/lib/domain/__tests__/oci-api-specification.js +23 -0
- package/lib/domain/container-image.js +8 -21
- package/lib/domain/oci-api-specification.js +3 -5
- package/lib/driver-logging.js +0 -19
- package/lib/driver.js +0 -4
- package/lib/drivers/docker-compose/__tests__/client.js +249 -0
- package/lib/drivers/docker-compose/__tests__/index.js +430 -0
- package/lib/drivers/docker-compose/client.js +0 -16
- package/lib/drivers/docker-compose/index.js +7 -49
- package/lib/errors.js +0 -10
- package/lib/http-proxy.js +28 -23
- package/lib/index.js +1 -9
- package/lib/middleware/__tests__/add-service-proxy-config.js +258 -0
- package/lib/middleware/__tests__/develop.js +120 -0
- package/lib/middleware/__tests__/helpers.js +154 -0
- package/lib/middleware/__tests__/port-override.js +125 -0
- package/lib/middleware/__tests__/set-env-vars.js +94 -0
- package/lib/middleware/__tests__/set-image.js +76 -0
- package/lib/middleware/__tests__/set-logging-driver.js +94 -0
- package/lib/middleware/__tests__/tag-override.js +92 -0
- package/lib/middleware/add-service-proxy-config.js +8 -16
- package/lib/middleware/develop.js +2 -5
- package/lib/middleware/helpers.js +6 -12
- package/lib/middleware/port-override.js +5 -8
- package/lib/middleware/set-env-vars.js +6 -6
- package/lib/middleware/set-image.js +4 -5
- package/lib/middleware/set-logging-driver.js +6 -6
- package/lib/middleware/tag-override.js +4 -6
- package/lib/navy/__tests__/default-middleware.js +40 -0
- package/lib/navy/__tests__/index.js +1612 -0
- package/lib/navy/__tests__/middleware.js +71 -0
- package/lib/navy/__tests__/plugin-interface.js +121 -0
- package/lib/navy/__tests__/state.js +103 -0
- package/lib/navy/__tests__/util.js +24 -0
- package/lib/navy/default-middleware.js +0 -10
- package/lib/navy/index.js +83 -138
- package/lib/navy/middleware.js +0 -6
- package/lib/navy/plugin-interface.js +2 -10
- package/lib/navy/state.js +12 -24
- package/lib/navy/util.js +0 -1
- package/lib/service.js +2 -3
- package/lib/util/__tests__/exec-async.js +83 -0
- package/lib/util/__tests__/external-ip.js +97 -2
- package/lib/util/__tests__/get-lan-ip.js +46 -0
- package/lib/util/__tests__/has-update.js +136 -0
- package/lib/util/__tests__/https.js +301 -0
- package/lib/util/__tests__/navyrc.js +45 -0
- package/lib/util/__tests__/service-host.js +63 -5
- package/lib/util/__tests__/table.js +44 -0
- package/lib/util/docker-client.js +2 -10
- package/lib/util/exec-async.js +0 -4
- package/lib/util/external-ip.js +8 -12
- package/lib/util/fs.js +1 -6
- package/lib/util/get-lan-ip.js +0 -5
- package/lib/util/has-update.js +2 -14
- package/lib/util/https.js +11 -55
- package/lib/util/navyrc.js +0 -5
- package/lib/util/service-host.js +0 -17
- package/lib/util/table.js +0 -6
- package/package.json +14 -13
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
var _chai = require("chai");
|
|
5
|
+
var _sinon = _interopRequireDefault(require("sinon"));
|
|
6
|
+
var _proxyquire = _interopRequireDefault(require("proxyquire"));
|
|
7
|
+
var _errors = require("../../../errors");
|
|
8
|
+
/* eslint-env mocha */
|
|
9
|
+
|
|
10
|
+
describe('cli/util/import', function () {
|
|
11
|
+
let sandbox;
|
|
12
|
+
let startDriverLoggingStub;
|
|
13
|
+
let stopDriverLoggingStub;
|
|
14
|
+
let consoleLogStub;
|
|
15
|
+
let navyStub;
|
|
16
|
+
let importNavy;
|
|
17
|
+
beforeEach(function () {
|
|
18
|
+
sandbox = _sinon.default.createSandbox();
|
|
19
|
+
navyStub = {
|
|
20
|
+
name: 'env-1',
|
|
21
|
+
isInitialised: sandbox.stub().resolves(false),
|
|
22
|
+
initialise: sandbox.stub().resolves(),
|
|
23
|
+
ensurePluginsLoaded: sandbox.stub().resolves(),
|
|
24
|
+
emitAsync: sandbox.stub().resolves(),
|
|
25
|
+
relaunch: sandbox.stub().resolves()
|
|
26
|
+
};
|
|
27
|
+
startDriverLoggingStub = sandbox.stub();
|
|
28
|
+
stopDriverLoggingStub = sandbox.stub();
|
|
29
|
+
consoleLogStub = sandbox.stub(console, 'log');
|
|
30
|
+
importNavy = _proxyquire.default.noCallThru()('../import', {
|
|
31
|
+
'../../driver-logging': {
|
|
32
|
+
startDriverLogging: startDriverLoggingStub,
|
|
33
|
+
stopDriverLogging: stopDriverLoggingStub
|
|
34
|
+
},
|
|
35
|
+
'../../errors': {
|
|
36
|
+
NavyError: _errors.NavyError
|
|
37
|
+
}
|
|
38
|
+
}).importNavy;
|
|
39
|
+
});
|
|
40
|
+
afterEach(function () {
|
|
41
|
+
sandbox.restore();
|
|
42
|
+
});
|
|
43
|
+
describe('importNavy', function () {
|
|
44
|
+
it('should throw a NavyError when the navy has already been initialised', async function () {
|
|
45
|
+
navyStub.isInitialised.resolves(true);
|
|
46
|
+
let caught;
|
|
47
|
+
try {
|
|
48
|
+
await importNavy(navyStub, {});
|
|
49
|
+
} catch (err) {
|
|
50
|
+
caught = err;
|
|
51
|
+
}
|
|
52
|
+
(0, _chai.expect)(caught).to.be.instanceof(_errors.NavyError);
|
|
53
|
+
(0, _chai.expect)(caught.message).to.contain('env-1');
|
|
54
|
+
(0, _chai.expect)(caught.message).to.contain('already been imported');
|
|
55
|
+
(0, _chai.expect)(navyStub.initialise.called).to.equal(false);
|
|
56
|
+
});
|
|
57
|
+
it('should initialise the navy with the provided opts', async function () {
|
|
58
|
+
const opts = {
|
|
59
|
+
configProvider: 'filesystem',
|
|
60
|
+
path: '/cwd'
|
|
61
|
+
};
|
|
62
|
+
await importNavy(navyStub, opts);
|
|
63
|
+
(0, _chai.expect)(navyStub.initialise.calledOnce).to.equal(true);
|
|
64
|
+
(0, _chai.expect)(navyStub.initialise.firstCall.args[0]).to.equal(opts);
|
|
65
|
+
});
|
|
66
|
+
it('should ensure plugins are loaded and emit cli.import in order before relaunch', async function () {
|
|
67
|
+
await importNavy(navyStub, {});
|
|
68
|
+
(0, _chai.expect)(navyStub.ensurePluginsLoaded.calledOnce).to.equal(true);
|
|
69
|
+
(0, _chai.expect)(navyStub.emitAsync.calledOnce).to.equal(true);
|
|
70
|
+
(0, _chai.expect)(navyStub.emitAsync.firstCall.args[0]).to.equal('cli.import');
|
|
71
|
+
(0, _chai.expect)(navyStub.relaunch.calledOnce).to.equal(true);
|
|
72
|
+
(0, _chai.expect)(navyStub.initialise.calledBefore(navyStub.ensurePluginsLoaded)).to.equal(true);
|
|
73
|
+
(0, _chai.expect)(navyStub.ensurePluginsLoaded.calledBefore(navyStub.emitAsync)).to.equal(true);
|
|
74
|
+
(0, _chai.expect)(navyStub.emitAsync.calledBefore(navyStub.relaunch)).to.equal(true);
|
|
75
|
+
});
|
|
76
|
+
it('should bracket relaunch with start/stopDriverLogging', async function () {
|
|
77
|
+
await importNavy(navyStub, {});
|
|
78
|
+
(0, _chai.expect)(startDriverLoggingStub.calledOnce).to.equal(true);
|
|
79
|
+
(0, _chai.expect)(stopDriverLoggingStub.calledOnce).to.equal(true);
|
|
80
|
+
(0, _chai.expect)(startDriverLoggingStub.calledBefore(navyStub.relaunch)).to.equal(true);
|
|
81
|
+
(0, _chai.expect)(navyStub.relaunch.calledBefore(stopDriverLoggingStub)).to.equal(true);
|
|
82
|
+
});
|
|
83
|
+
it('should log a success message containing the navy name', async function () {
|
|
84
|
+
await importNavy(navyStub, {});
|
|
85
|
+
const printed = consoleLogStub.getCalls().map(c => c.args[0] || '').join(' ');
|
|
86
|
+
(0, _chai.expect)(printed).to.contain('env-1');
|
|
87
|
+
(0, _chai.expect)(printed).to.contain('imported and initialised');
|
|
88
|
+
});
|
|
89
|
+
it('should print a labelled line for each known option key', async function () {
|
|
90
|
+
const opts = {
|
|
91
|
+
configProvider: 'filesystem',
|
|
92
|
+
path: '/cwd',
|
|
93
|
+
npmPackage: 'some-pkg'
|
|
94
|
+
};
|
|
95
|
+
await importNavy(navyStub, opts);
|
|
96
|
+
const printed = consoleLogStub.getCalls().map(c => c.args[0] || '').join('\n');
|
|
97
|
+
(0, _chai.expect)(printed).to.contain('Provider');
|
|
98
|
+
(0, _chai.expect)(printed).to.contain('filesystem');
|
|
99
|
+
(0, _chai.expect)(printed).to.contain('Directory');
|
|
100
|
+
(0, _chai.expect)(printed).to.contain('/cwd');
|
|
101
|
+
(0, _chai.expect)(printed).to.contain('NPM Package');
|
|
102
|
+
(0, _chai.expect)(printed).to.contain('some-pkg');
|
|
103
|
+
});
|
|
104
|
+
it('should ignore unknown option keys when printing labels', async function () {
|
|
105
|
+
const opts = {
|
|
106
|
+
configProvider: 'filesystem',
|
|
107
|
+
unrecognised: 'value'
|
|
108
|
+
};
|
|
109
|
+
await importNavy(navyStub, opts);
|
|
110
|
+
const printed = consoleLogStub.getCalls().map(c => c.args[0] || '').join('\n');
|
|
111
|
+
(0, _chai.expect)(printed).to.contain('Provider');
|
|
112
|
+
(0, _chai.expect)(printed).to.not.contain('unrecognised');
|
|
113
|
+
(0, _chai.expect)(printed).to.not.contain('value');
|
|
114
|
+
});
|
|
115
|
+
it('should not print any option label lines when no known options are supplied', async function () {
|
|
116
|
+
await importNavy(navyStub, {});
|
|
117
|
+
const printed = consoleLogStub.getCalls().map(c => c.args[0] || '').join('\n');
|
|
118
|
+
(0, _chai.expect)(printed).to.not.contain('Provider');
|
|
119
|
+
(0, _chai.expect)(printed).to.not.contain('Directory');
|
|
120
|
+
(0, _chai.expect)(printed).to.not.contain('NPM Package');
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _chai = require("chai");
|
|
4
|
+
var cliUtil = _interopRequireWildcard(require("../index"));
|
|
5
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
6
|
+
/* eslint-env mocha */
|
|
7
|
+
|
|
8
|
+
describe('cli/util/index', function () {
|
|
9
|
+
describe('module exports', function () {
|
|
10
|
+
it('should re-export getOrInitialiseNavy as a function', function () {
|
|
11
|
+
(0, _chai.expect)(cliUtil).to.have.property('getOrInitialiseNavy').that.is.a('function');
|
|
12
|
+
});
|
|
13
|
+
it('should re-export importNavy as a function', function () {
|
|
14
|
+
(0, _chai.expect)(cliUtil).to.have.property('importNavy').that.is.a('function');
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
var _chai = require("chai");
|
|
5
|
+
var _sinon = _interopRequireDefault(require("sinon"));
|
|
6
|
+
var _mergeActionOptions = require("../merge-action-options");
|
|
7
|
+
/* eslint-env mocha */
|
|
8
|
+
|
|
9
|
+
describe('cli/util/merge-action-options', function () {
|
|
10
|
+
it('should return parsed opts when command is missing', function () {
|
|
11
|
+
const opts = {
|
|
12
|
+
navy: 'dev'
|
|
13
|
+
};
|
|
14
|
+
(0, _chai.expect)((0, _mergeActionOptions.mergeActionOptions)(opts, null)).to.equal(opts);
|
|
15
|
+
});
|
|
16
|
+
it('should return parsed opts when optsWithGlobals is missing', function () {
|
|
17
|
+
const opts = {
|
|
18
|
+
navy: 'dev'
|
|
19
|
+
};
|
|
20
|
+
(0, _chai.expect)((0, _mergeActionOptions.mergeActionOptions)(opts, {})).to.equal(opts);
|
|
21
|
+
});
|
|
22
|
+
it('should merge optsWithGlobals so global navy wins over subcommand defaults', function () {
|
|
23
|
+
const command = {
|
|
24
|
+
optsWithGlobals: () => ({
|
|
25
|
+
navy: 'dev',
|
|
26
|
+
json: true
|
|
27
|
+
})
|
|
28
|
+
};
|
|
29
|
+
const merged = (0, _mergeActionOptions.mergeActionOptions)({
|
|
30
|
+
navy: 'default',
|
|
31
|
+
json: false
|
|
32
|
+
}, command);
|
|
33
|
+
(0, _chai.expect)(merged.navy).to.equal('dev');
|
|
34
|
+
(0, _chai.expect)(merged.json).to.equal(true);
|
|
35
|
+
});
|
|
36
|
+
it('should call optsWithGlobals on the command', function () {
|
|
37
|
+
const spy = _sinon.default.stub().returns({
|
|
38
|
+
navy: 'x'
|
|
39
|
+
});
|
|
40
|
+
(0, _mergeActionOptions.mergeActionOptions)({
|
|
41
|
+
navy: 'y'
|
|
42
|
+
}, {
|
|
43
|
+
optsWithGlobals: spy
|
|
44
|
+
});
|
|
45
|
+
(0, _chai.expect)(spy.calledOnce).to.equal(true);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
var _chai = require("chai");
|
|
5
|
+
var _sinon = _interopRequireDefault(require("sinon"));
|
|
6
|
+
var _proxyquire = _interopRequireDefault(require("proxyquire"));
|
|
7
|
+
/* eslint-env mocha */
|
|
8
|
+
|
|
9
|
+
describe('cli/util/reconfigure', function () {
|
|
10
|
+
let sandbox;
|
|
11
|
+
let getLaunchedNaviesStub;
|
|
12
|
+
let startDriverLoggingStub;
|
|
13
|
+
let stopDriverLoggingStub;
|
|
14
|
+
let reconfigureAllNavies;
|
|
15
|
+
beforeEach(function () {
|
|
16
|
+
sandbox = _sinon.default.createSandbox();
|
|
17
|
+
getLaunchedNaviesStub = sandbox.stub();
|
|
18
|
+
startDriverLoggingStub = sandbox.stub();
|
|
19
|
+
stopDriverLoggingStub = sandbox.stub();
|
|
20
|
+
reconfigureAllNavies = _proxyquire.default.noCallThru()('../reconfigure', {
|
|
21
|
+
'../../': {
|
|
22
|
+
getLaunchedNavies: getLaunchedNaviesStub
|
|
23
|
+
},
|
|
24
|
+
'../../driver-logging': {
|
|
25
|
+
startDriverLogging: startDriverLoggingStub,
|
|
26
|
+
stopDriverLogging: stopDriverLoggingStub
|
|
27
|
+
}
|
|
28
|
+
}).reconfigureAllNavies;
|
|
29
|
+
});
|
|
30
|
+
afterEach(function () {
|
|
31
|
+
sandbox.restore();
|
|
32
|
+
});
|
|
33
|
+
describe('reconfigureAllNavies', function () {
|
|
34
|
+
it('should be a no-op when there are no launched navies', async function () {
|
|
35
|
+
getLaunchedNaviesStub.resolves([]);
|
|
36
|
+
await reconfigureAllNavies();
|
|
37
|
+
(0, _chai.expect)(getLaunchedNaviesStub.calledOnce).to.equal(true);
|
|
38
|
+
(0, _chai.expect)(startDriverLoggingStub.called).to.equal(false);
|
|
39
|
+
(0, _chai.expect)(stopDriverLoggingStub.called).to.equal(false);
|
|
40
|
+
});
|
|
41
|
+
it('should reconfigure each launched navy in turn with bracketed driver logging', async function () {
|
|
42
|
+
const navyA = {
|
|
43
|
+
name: 'envA',
|
|
44
|
+
reconfigure: sandbox.stub().resolves()
|
|
45
|
+
};
|
|
46
|
+
const navyB = {
|
|
47
|
+
name: 'envB',
|
|
48
|
+
reconfigure: sandbox.stub().resolves()
|
|
49
|
+
};
|
|
50
|
+
getLaunchedNaviesStub.resolves([navyA, navyB]);
|
|
51
|
+
await reconfigureAllNavies();
|
|
52
|
+
(0, _chai.expect)(navyA.reconfigure.calledOnce).to.equal(true);
|
|
53
|
+
(0, _chai.expect)(navyB.reconfigure.calledOnce).to.equal(true);
|
|
54
|
+
(0, _chai.expect)(startDriverLoggingStub.callCount).to.equal(2);
|
|
55
|
+
(0, _chai.expect)(stopDriverLoggingStub.callCount).to.equal(2);
|
|
56
|
+
});
|
|
57
|
+
it('should pass a message that includes the navy name to startDriverLogging', async function () {
|
|
58
|
+
const navy = {
|
|
59
|
+
name: 'envA',
|
|
60
|
+
reconfigure: sandbox.stub().resolves()
|
|
61
|
+
};
|
|
62
|
+
getLaunchedNaviesStub.resolves([navy]);
|
|
63
|
+
await reconfigureAllNavies();
|
|
64
|
+
(0, _chai.expect)(startDriverLoggingStub.firstCall.args[0]).to.contain('envA');
|
|
65
|
+
(0, _chai.expect)(startDriverLoggingStub.firstCall.args[0]).to.contain('Reconfiguring');
|
|
66
|
+
});
|
|
67
|
+
it('should call startDriverLogging before each reconfigure and stopDriverLogging after', async function () {
|
|
68
|
+
const navy = {
|
|
69
|
+
name: 'envA',
|
|
70
|
+
reconfigure: sandbox.stub().resolves()
|
|
71
|
+
};
|
|
72
|
+
getLaunchedNaviesStub.resolves([navy]);
|
|
73
|
+
await reconfigureAllNavies();
|
|
74
|
+
(0, _chai.expect)(startDriverLoggingStub.calledBefore(navy.reconfigure)).to.equal(true);
|
|
75
|
+
(0, _chai.expect)(navy.reconfigure.calledBefore(stopDriverLoggingStub)).to.equal(true);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
});
|
|
@@ -1,24 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
-
|
|
5
4
|
Object.defineProperty(exports, "__esModule", {
|
|
6
5
|
value: true
|
|
7
6
|
});
|
|
8
7
|
exports.getOrInitialiseNavy = getOrInitialiseNavy;
|
|
9
|
-
|
|
10
8
|
var _ = require("../../");
|
|
11
|
-
|
|
12
9
|
var _import = require("./import");
|
|
13
|
-
|
|
14
10
|
var _filesystem = _interopRequireDefault(require("../../config-providers/filesystem"));
|
|
15
|
-
|
|
16
11
|
async function getOrInitialiseNavy(navyName) {
|
|
17
12
|
const navy = (0, _.getNavy)(navyName);
|
|
18
|
-
|
|
19
13
|
if (!(await navy.isInitialised())) {
|
|
20
14
|
await (0, _import.importNavy)(navy, await _filesystem.default.getImportOptionsForCLI({}));
|
|
21
15
|
}
|
|
22
|
-
|
|
23
16
|
return navy;
|
|
24
17
|
}
|
package/lib/cli/util/import.js
CHANGED
|
@@ -1,29 +1,22 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
-
|
|
5
4
|
Object.defineProperty(exports, "__esModule", {
|
|
6
5
|
value: true
|
|
7
6
|
});
|
|
8
7
|
exports.importNavy = importNavy;
|
|
9
|
-
|
|
10
8
|
var _chalk = _interopRequireDefault(require("chalk"));
|
|
11
|
-
|
|
12
9
|
var _driverLogging = require("../../driver-logging");
|
|
13
|
-
|
|
14
10
|
var _errors = require("../../errors");
|
|
15
|
-
|
|
16
11
|
const OPTION_LABEL_MAP = {
|
|
17
12
|
configProvider: 'Provider',
|
|
18
13
|
path: 'Directory',
|
|
19
14
|
npmPackage: 'NPM Package'
|
|
20
15
|
};
|
|
21
|
-
|
|
22
16
|
async function importNavy(navy, initialiseOpts) {
|
|
23
17
|
if (await navy.isInitialised()) {
|
|
24
18
|
throw new _errors.NavyError(`Navy "${navy.name}" has already been imported and initialised.`);
|
|
25
19
|
}
|
|
26
|
-
|
|
27
20
|
await navy.initialise(initialiseOpts);
|
|
28
21
|
await navy.ensurePluginsLoaded();
|
|
29
22
|
await navy.emitAsync('cli.import');
|
|
@@ -33,12 +26,10 @@ async function importNavy(navy, initialiseOpts) {
|
|
|
33
26
|
console.log();
|
|
34
27
|
console.log(_chalk.default.green(` Navy "${_chalk.default.white.bold(navy.name)}" has now been imported and initialised. 🎉`));
|
|
35
28
|
console.log();
|
|
36
|
-
|
|
37
29
|
for (const key in initialiseOpts) {
|
|
38
30
|
if (OPTION_LABEL_MAP[key]) {
|
|
39
31
|
console.log(` ${_chalk.default.bold(OPTION_LABEL_MAP[key])}: ${_chalk.default.dim(initialiseOpts[key])}`);
|
|
40
32
|
}
|
|
41
33
|
}
|
|
42
|
-
|
|
43
34
|
console.log();
|
|
44
35
|
}
|
package/lib/cli/util/index.js
CHANGED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.mergeActionOptions = mergeActionOptions;
|
|
7
|
+
/**
|
|
8
|
+
* Merge Commander's per-command opts with inherited globals (e.g. `navy -e dev ps`).
|
|
9
|
+
* `optsWithGlobals()` is the combined view; spread it after local opts so globals
|
|
10
|
+
* override stale option defaults on the subcommand.
|
|
11
|
+
*/
|
|
12
|
+
function mergeActionOptions(parsedOpts, command) {
|
|
13
|
+
if (!command || typeof command.optsWithGlobals !== 'function') {
|
|
14
|
+
return parsedOpts;
|
|
15
|
+
}
|
|
16
|
+
return {
|
|
17
|
+
...parsedOpts,
|
|
18
|
+
...command.optsWithGlobals()
|
|
19
|
+
};
|
|
20
|
+
}
|
|
@@ -4,14 +4,10 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
6
|
exports.reconfigureAllNavies = reconfigureAllNavies;
|
|
7
|
-
|
|
8
7
|
var _ = require("../../");
|
|
9
|
-
|
|
10
8
|
var _driverLogging = require("../../driver-logging");
|
|
11
|
-
|
|
12
9
|
async function reconfigureAllNavies() {
|
|
13
10
|
const navies = await (0, _.getLaunchedNavies)();
|
|
14
|
-
|
|
15
11
|
for (const navy of navies) {
|
|
16
12
|
(0, _driverLogging.startDriverLogging)('Reconfiguring ' + navy.name);
|
|
17
13
|
await navy.reconfigure();
|
|
@@ -1,71 +1,51 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
-
|
|
5
4
|
Object.defineProperty(exports, "__esModule", {
|
|
6
5
|
value: true
|
|
7
6
|
});
|
|
8
7
|
exports.default = _default;
|
|
9
|
-
|
|
10
8
|
var _chalk = _interopRequireDefault(require("chalk"));
|
|
11
|
-
|
|
12
9
|
var _readline = _interopRequireDefault(require("readline"));
|
|
13
|
-
|
|
14
10
|
var _cliSpinners = require("cli-spinners");
|
|
15
|
-
|
|
16
11
|
var _ = require("../");
|
|
17
|
-
|
|
18
12
|
let spinnerIndex = 0;
|
|
19
13
|
let spinnerFrame = _cliSpinners.dots.frames[0];
|
|
20
|
-
|
|
21
14
|
async function _default(services, opts) {
|
|
22
15
|
const navy = (0, _.getNavy)(opts.navy);
|
|
23
16
|
const servicesToCheck = services.length === 0 ? undefined : services;
|
|
24
|
-
|
|
25
17
|
if (!process.stdout.isTTY) {
|
|
26
18
|
await navy.waitForHealthy(servicesToCheck);
|
|
27
19
|
console.log('Now available');
|
|
28
20
|
return;
|
|
29
21
|
}
|
|
30
|
-
|
|
31
22
|
let healthyStatus = [];
|
|
32
23
|
let drawnLines = 0;
|
|
33
|
-
|
|
34
24
|
function draw() {
|
|
35
25
|
drawnLines = 0;
|
|
36
|
-
|
|
37
26
|
if (healthyStatus.length === 0) {
|
|
38
27
|
console.log('Waiting');
|
|
39
28
|
drawnLines = 1;
|
|
40
29
|
return;
|
|
41
30
|
}
|
|
42
|
-
|
|
43
31
|
const lines = healthyStatus.map(service => `${service.health !== 'healthy' ? _chalk.default.yellow(spinnerFrame) : _chalk.default.green('✔')} ${service.service}`);
|
|
44
32
|
drawnLines = lines.length;
|
|
45
33
|
console.log(lines.join('\n'));
|
|
46
34
|
}
|
|
47
|
-
|
|
48
35
|
function redraw() {
|
|
49
36
|
_readline.default.clearLine(process.stdout, 0);
|
|
50
|
-
|
|
51
37
|
_readline.default.cursorTo(process.stdout, 0);
|
|
52
|
-
|
|
53
38
|
for (let i = 0; i < drawnLines; i++) {
|
|
54
39
|
_readline.default.moveCursor(process.stdout, 0, -1);
|
|
55
|
-
|
|
56
40
|
_readline.default.clearLine(process.stdout, 0);
|
|
57
41
|
}
|
|
58
|
-
|
|
59
42
|
draw();
|
|
60
43
|
}
|
|
61
|
-
|
|
62
44
|
const spinner = setInterval(() => {
|
|
63
45
|
spinnerIndex++;
|
|
64
|
-
|
|
65
46
|
if (spinnerIndex >= _cliSpinners.dots.frames.length) {
|
|
66
47
|
spinnerIndex = 0;
|
|
67
48
|
}
|
|
68
|
-
|
|
69
49
|
spinnerFrame = _cliSpinners.dots.frames[spinnerIndex];
|
|
70
50
|
redraw();
|
|
71
51
|
}, _cliSpinners.dots.interval);
|
|
@@ -74,5 +54,4 @@ async function _default(services, opts) {
|
|
|
74
54
|
redraw();
|
|
75
55
|
clearInterval(spinner);
|
|
76
56
|
}
|
|
77
|
-
|
|
78
57
|
module.exports = exports.default;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
var _chai = require("chai");
|
|
5
|
+
var _sinon = _interopRequireDefault(require("sinon"));
|
|
6
|
+
var execAsyncModule = _interopRequireWildcard(require("../../../util/exec-async"));
|
|
7
|
+
var _containerImage = require("../../../domain/container-image");
|
|
8
|
+
var _getCredentials = _interopRequireDefault(require("../get-credentials"));
|
|
9
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
10
|
+
/* eslint-env mocha */
|
|
11
|
+
|
|
12
|
+
describe('get-credentials', function () {
|
|
13
|
+
let sandbox;
|
|
14
|
+
beforeEach(function () {
|
|
15
|
+
sandbox = _sinon.default.createSandbox();
|
|
16
|
+
});
|
|
17
|
+
afterEach(function () {
|
|
18
|
+
sandbox.restore();
|
|
19
|
+
});
|
|
20
|
+
it('should call docker-credential-desktop with the default auth URL when registry is the default registry', async function () {
|
|
21
|
+
const execStub = sandbox.stub(execAsyncModule, 'execAsync').resolves(JSON.stringify({
|
|
22
|
+
Username: 'u',
|
|
23
|
+
Secret: 's'
|
|
24
|
+
}));
|
|
25
|
+
const result = await (0, _getCredentials.default)(_containerImage.DEFAULT_REGISTRY);
|
|
26
|
+
(0, _chai.expect)(result).to.eql({
|
|
27
|
+
username: 'u',
|
|
28
|
+
password: 's'
|
|
29
|
+
});
|
|
30
|
+
const args = execStub.firstCall.args;
|
|
31
|
+
(0, _chai.expect)(args[0]).to.equal('echo');
|
|
32
|
+
(0, _chai.expect)(args[1]).to.include(_containerImage.DEFAULT_REGISTRY_AUTH);
|
|
33
|
+
(0, _chai.expect)(args[1]).to.include('docker-credential-desktop');
|
|
34
|
+
(0, _chai.expect)(args[1]).to.include('get');
|
|
35
|
+
});
|
|
36
|
+
it('should pass the registry hostname directly when not the default registry', async function () {
|
|
37
|
+
const execStub = sandbox.stub(execAsyncModule, 'execAsync').resolves(JSON.stringify({
|
|
38
|
+
Username: 'alice',
|
|
39
|
+
Secret: 'pw'
|
|
40
|
+
}));
|
|
41
|
+
const result = await (0, _getCredentials.default)('myregistry.local:5000');
|
|
42
|
+
(0, _chai.expect)(result).to.eql({
|
|
43
|
+
username: 'alice',
|
|
44
|
+
password: 'pw'
|
|
45
|
+
});
|
|
46
|
+
(0, _chai.expect)(execStub.firstCall.args[1]).to.include('myregistry.local:5000');
|
|
47
|
+
});
|
|
48
|
+
it('should return empty credentials when execAsync rejects', async function () {
|
|
49
|
+
sandbox.stub(execAsyncModule, 'execAsync').rejects(new Error('not installed'));
|
|
50
|
+
(0, _chai.expect)(await (0, _getCredentials.default)('any')).to.eql({
|
|
51
|
+
username: '',
|
|
52
|
+
password: ''
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
it('should return empty credentials when stdout is not valid JSON', async function () {
|
|
56
|
+
sandbox.stub(execAsyncModule, 'execAsync').resolves('not-json');
|
|
57
|
+
(0, _chai.expect)(await (0, _getCredentials.default)('any')).to.eql({
|
|
58
|
+
username: '',
|
|
59
|
+
password: ''
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
});
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
var _chai = require("chai");
|
|
5
|
+
var _sinon = _interopRequireDefault(require("sinon"));
|
|
6
|
+
var _nock = _interopRequireDefault(require("nock"));
|
|
7
|
+
var _proxyquire = _interopRequireDefault(require("proxyquire"));
|
|
8
|
+
/* eslint-env mocha */
|
|
9
|
+
|
|
10
|
+
function loadModule({
|
|
11
|
+
getCredentials,
|
|
12
|
+
getToken
|
|
13
|
+
} = {}) {
|
|
14
|
+
return _proxyquire.default.noCallThru()('../get-endpoint', {
|
|
15
|
+
'./get-credentials': getCredentials || _sinon.default.stub().resolves({
|
|
16
|
+
username: 'u',
|
|
17
|
+
password: 'p'
|
|
18
|
+
}),
|
|
19
|
+
'./get-token': getToken || _sinon.default.stub().resolves('the-token')
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
describe('get-endpoint', function () {
|
|
23
|
+
afterEach(function () {
|
|
24
|
+
_nock.default.cleanAll();
|
|
25
|
+
});
|
|
26
|
+
it('should return the response when the registry replies 200', async function () {
|
|
27
|
+
const body = {
|
|
28
|
+
schemaVersion: 2
|
|
29
|
+
};
|
|
30
|
+
(0, _nock.default)('https://reg.example.com').get('/v2/library/node/manifests/latest').reply(200, body);
|
|
31
|
+
const getEndpoint = loadModule();
|
|
32
|
+
const response = await getEndpoint({
|
|
33
|
+
registry: 'reg.example.com',
|
|
34
|
+
endpoint: 'library/node/manifests/latest'
|
|
35
|
+
});
|
|
36
|
+
(0, _chai.expect)(response.status).to.equal(200);
|
|
37
|
+
(0, _chai.expect)(await response.json()).to.eql(body);
|
|
38
|
+
});
|
|
39
|
+
it('should throw "Operation not found" when the registry returns 404', async function () {
|
|
40
|
+
(0, _nock.default)('https://reg.example.com').get('/v2/missing').reply(404, {
|
|
41
|
+
errors: []
|
|
42
|
+
});
|
|
43
|
+
const getEndpoint = loadModule();
|
|
44
|
+
let caught;
|
|
45
|
+
try {
|
|
46
|
+
await getEndpoint({
|
|
47
|
+
registry: 'reg.example.com',
|
|
48
|
+
endpoint: 'missing'
|
|
49
|
+
});
|
|
50
|
+
} catch (err) {
|
|
51
|
+
caught = err;
|
|
52
|
+
}
|
|
53
|
+
(0, _chai.expect)(caught).to.be.an('error');
|
|
54
|
+
(0, _chai.expect)(caught.message).to.equal('Operation not found');
|
|
55
|
+
});
|
|
56
|
+
it('should retry with a Bearer token when the response is 401 with a Bearer challenge', async function () {
|
|
57
|
+
(0, _nock.default)('https://reg.example.com').get('/v2/secret').reply(401, '', {
|
|
58
|
+
'WWW-Authenticate': 'Bearer realm="https://auth.example.com/token",service="reg.example.com",scope="repository:secret:pull"'
|
|
59
|
+
}).get('/v2/secret').matchHeader('authorization', 'Bearer the-token').reply(200, {
|
|
60
|
+
ok: true
|
|
61
|
+
});
|
|
62
|
+
const getToken = _sinon.default.stub().resolves('the-token');
|
|
63
|
+
const getEndpoint = loadModule({
|
|
64
|
+
getToken
|
|
65
|
+
});
|
|
66
|
+
const response = await getEndpoint({
|
|
67
|
+
registry: 'reg.example.com',
|
|
68
|
+
endpoint: 'secret'
|
|
69
|
+
});
|
|
70
|
+
(0, _chai.expect)(response.status).to.equal(200);
|
|
71
|
+
(0, _chai.expect)(await response.json()).to.eql({
|
|
72
|
+
ok: true
|
|
73
|
+
});
|
|
74
|
+
(0, _chai.expect)(getToken.calledOnce).to.equal(true);
|
|
75
|
+
});
|
|
76
|
+
it('should throw "Access denied" when the bearer-token retry still returns 401', async function () {
|
|
77
|
+
(0, _nock.default)('https://reg.example.com').get('/v2/secret').reply(401, '', {
|
|
78
|
+
'WWW-Authenticate': 'Bearer realm="https://auth.example.com/token",service="reg.example.com",scope="repository:secret:pull"'
|
|
79
|
+
}).get('/v2/secret').reply(401, '');
|
|
80
|
+
const getEndpoint = loadModule();
|
|
81
|
+
let caught;
|
|
82
|
+
try {
|
|
83
|
+
await getEndpoint({
|
|
84
|
+
registry: 'reg.example.com',
|
|
85
|
+
endpoint: 'secret'
|
|
86
|
+
});
|
|
87
|
+
} catch (err) {
|
|
88
|
+
caught = err;
|
|
89
|
+
}
|
|
90
|
+
(0, _chai.expect)(caught.message).to.equal('Access denied');
|
|
91
|
+
});
|
|
92
|
+
it('should throw "Invalid authentication" for a Basic challenge', async function () {
|
|
93
|
+
(0, _nock.default)('https://reg.example.com').get('/v2/needs-basic').reply(401, '', {
|
|
94
|
+
'WWW-Authenticate': 'Basic realm="reg"'
|
|
95
|
+
});
|
|
96
|
+
const getEndpoint = loadModule();
|
|
97
|
+
let caught;
|
|
98
|
+
try {
|
|
99
|
+
await getEndpoint({
|
|
100
|
+
registry: 'reg.example.com',
|
|
101
|
+
endpoint: 'needs-basic'
|
|
102
|
+
});
|
|
103
|
+
} catch (err) {
|
|
104
|
+
caught = err;
|
|
105
|
+
}
|
|
106
|
+
(0, _chai.expect)(caught.message).to.equal('Invalid authentication');
|
|
107
|
+
});
|
|
108
|
+
it('should throw "Invalid authentication" for an unknown auth scheme', async function () {
|
|
109
|
+
(0, _nock.default)('https://reg.example.com').get('/v2/weird').reply(401, '', {
|
|
110
|
+
'WWW-Authenticate': 'Digest realm="reg"'
|
|
111
|
+
});
|
|
112
|
+
const getEndpoint = loadModule();
|
|
113
|
+
let caught;
|
|
114
|
+
try {
|
|
115
|
+
await getEndpoint({
|
|
116
|
+
registry: 'reg.example.com',
|
|
117
|
+
endpoint: 'weird'
|
|
118
|
+
});
|
|
119
|
+
} catch (err) {
|
|
120
|
+
caught = err;
|
|
121
|
+
}
|
|
122
|
+
(0, _chai.expect)(caught.message).to.equal('Invalid authentication');
|
|
123
|
+
});
|
|
124
|
+
});
|