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.
Files changed (149) hide show
  1. package/lib/__tests__/config-provider.js +75 -0
  2. package/lib/__tests__/config.js +130 -0
  3. package/lib/__tests__/driver-logging.js +148 -0
  4. package/lib/__tests__/driver.js +19 -0
  5. package/lib/__tests__/errors.js +49 -0
  6. package/lib/__tests__/http-proxy.js +214 -0
  7. package/lib/__tests__/index.js +25 -0
  8. package/lib/__tests__/service.js +16 -0
  9. package/lib/cli/__tests__/develop.js +239 -0
  10. package/lib/cli/__tests__/external-ip.js +68 -0
  11. package/lib/cli/__tests__/health.js +257 -0
  12. package/lib/cli/__tests__/https.js +210 -0
  13. package/lib/cli/__tests__/import.js +110 -0
  14. package/lib/cli/__tests__/index.js +118 -0
  15. package/lib/cli/__tests__/lan-ip.js +90 -0
  16. package/lib/cli/__tests__/launch.js +179 -0
  17. package/lib/cli/__tests__/live.js +155 -0
  18. package/lib/cli/__tests__/local-ip.js +72 -0
  19. package/lib/cli/__tests__/logs.js +52 -0
  20. package/lib/cli/__tests__/open.js +65 -0
  21. package/lib/cli/__tests__/program.js +472 -0
  22. package/lib/cli/__tests__/ps.js +345 -0
  23. package/lib/cli/__tests__/refresh-config.js +95 -0
  24. package/lib/cli/__tests__/run.js +54 -0
  25. package/lib/cli/__tests__/status.js +204 -0
  26. package/lib/cli/__tests__/updates.js +243 -0
  27. package/lib/cli/__tests__/wait-for-healthy.js +134 -0
  28. package/lib/cli/config/__tests__/index.js +275 -0
  29. package/lib/cli/config/__tests__/wrapper.js +53 -0
  30. package/lib/cli/config/index.js +19 -37
  31. package/lib/cli/config/wrapper.js +0 -6
  32. package/lib/cli/develop.js +7 -21
  33. package/lib/cli/doctor/__tests__/clean-compose-files.js +78 -0
  34. package/lib/cli/doctor/__tests__/index.js +67 -0
  35. package/lib/cli/doctor/__tests__/invalid-compose-config.js +103 -0
  36. package/lib/cli/doctor/__tests__/invalid-state.js +83 -0
  37. package/lib/cli/doctor/__tests__/util.js +91 -0
  38. package/lib/cli/doctor/clean-compose-files.js +5 -13
  39. package/lib/cli/doctor/index.js +0 -12
  40. package/lib/cli/doctor/invalid-compose-config.js +0 -4
  41. package/lib/cli/doctor/invalid-state.js +0 -6
  42. package/lib/cli/doctor/util.js +0 -10
  43. package/lib/cli/external-ip.js +0 -4
  44. package/lib/cli/health.js +0 -12
  45. package/lib/cli/https.js +9 -25
  46. package/lib/cli/import.js +0 -12
  47. package/lib/cli/index.js +0 -9
  48. package/lib/cli/lan-ip.js +2 -8
  49. package/lib/cli/launch.js +0 -9
  50. package/lib/cli/live.js +6 -16
  51. package/lib/cli/local-ip.js +2 -7
  52. package/lib/cli/logs.js +0 -3
  53. package/lib/cli/open.js +2 -7
  54. package/lib/cli/program.js +73 -101
  55. package/lib/cli/ps.js +1 -21
  56. package/lib/cli/refresh-config.js +0 -7
  57. package/lib/cli/run.js +0 -3
  58. package/lib/cli/status.js +0 -11
  59. package/lib/cli/updates.js +0 -22
  60. package/lib/cli/util/__tests__/get-or-initialise-navy.js +66 -0
  61. package/lib/cli/util/__tests__/import.js +123 -0
  62. package/lib/cli/util/__tests__/index.js +17 -0
  63. package/lib/cli/util/__tests__/merge-action-options.js +47 -0
  64. package/lib/cli/util/__tests__/reconfigure.js +78 -0
  65. package/lib/cli/util/get-or-initialise-navy.js +0 -7
  66. package/lib/cli/util/import.js +0 -9
  67. package/lib/cli/util/index.js +0 -2
  68. package/lib/cli/util/merge-action-options.js +20 -0
  69. package/lib/cli/util/reconfigure.js +0 -4
  70. package/lib/cli/wait-for-healthy.js +0 -21
  71. package/lib/client/registry/__tests__/get-credentials.js +62 -0
  72. package/lib/client/registry/__tests__/get-endpoint.js +124 -0
  73. package/lib/client/registry/__tests__/get-fat-manifest.js +67 -0
  74. package/lib/client/registry/__tests__/get-token.js +66 -0
  75. package/lib/client/registry/__tests__/helpers.js +26 -0
  76. package/lib/client/registry/get-credentials.js +3 -9
  77. package/lib/client/registry/get-endpoint.js +29 -63
  78. package/lib/client/registry/get-fat-manifest.js +2 -9
  79. package/lib/client/registry/get-token.js +2 -13
  80. package/lib/client/registry/helpers.js +0 -4
  81. package/lib/config-provider.js +0 -12
  82. package/lib/config-providers/filesystem/__tests__/index.js +176 -0
  83. package/lib/config-providers/filesystem/index.js +5 -23
  84. package/lib/config-providers/npm/__tests__/index.js +226 -0
  85. package/lib/config-providers/npm/__tests__/util.js +1 -2
  86. package/lib/config-providers/npm/index.js +12 -35
  87. package/lib/config-providers/npm/util.js +0 -3
  88. package/lib/config.js +4 -19
  89. package/lib/domain/__tests__/container-image.js +81 -0
  90. package/lib/domain/__tests__/oci-api-specification.js +23 -0
  91. package/lib/domain/container-image.js +8 -21
  92. package/lib/domain/oci-api-specification.js +3 -5
  93. package/lib/driver-logging.js +0 -19
  94. package/lib/driver.js +0 -4
  95. package/lib/drivers/docker-compose/__tests__/client.js +249 -0
  96. package/lib/drivers/docker-compose/__tests__/index.js +430 -0
  97. package/lib/drivers/docker-compose/client.js +0 -16
  98. package/lib/drivers/docker-compose/index.js +7 -49
  99. package/lib/errors.js +0 -10
  100. package/lib/http-proxy.js +28 -23
  101. package/lib/index.js +1 -9
  102. package/lib/middleware/__tests__/add-service-proxy-config.js +258 -0
  103. package/lib/middleware/__tests__/develop.js +120 -0
  104. package/lib/middleware/__tests__/helpers.js +154 -0
  105. package/lib/middleware/__tests__/port-override.js +125 -0
  106. package/lib/middleware/__tests__/set-env-vars.js +94 -0
  107. package/lib/middleware/__tests__/set-image.js +76 -0
  108. package/lib/middleware/__tests__/set-logging-driver.js +94 -0
  109. package/lib/middleware/__tests__/tag-override.js +92 -0
  110. package/lib/middleware/add-service-proxy-config.js +8 -16
  111. package/lib/middleware/develop.js +2 -5
  112. package/lib/middleware/helpers.js +6 -12
  113. package/lib/middleware/port-override.js +5 -8
  114. package/lib/middleware/set-env-vars.js +6 -6
  115. package/lib/middleware/set-image.js +4 -5
  116. package/lib/middleware/set-logging-driver.js +6 -6
  117. package/lib/middleware/tag-override.js +4 -6
  118. package/lib/navy/__tests__/default-middleware.js +40 -0
  119. package/lib/navy/__tests__/index.js +1612 -0
  120. package/lib/navy/__tests__/middleware.js +71 -0
  121. package/lib/navy/__tests__/plugin-interface.js +121 -0
  122. package/lib/navy/__tests__/state.js +103 -0
  123. package/lib/navy/__tests__/util.js +24 -0
  124. package/lib/navy/default-middleware.js +0 -10
  125. package/lib/navy/index.js +83 -138
  126. package/lib/navy/middleware.js +0 -6
  127. package/lib/navy/plugin-interface.js +2 -10
  128. package/lib/navy/state.js +12 -24
  129. package/lib/navy/util.js +0 -1
  130. package/lib/service.js +2 -3
  131. package/lib/util/__tests__/exec-async.js +83 -0
  132. package/lib/util/__tests__/external-ip.js +97 -2
  133. package/lib/util/__tests__/get-lan-ip.js +46 -0
  134. package/lib/util/__tests__/has-update.js +136 -0
  135. package/lib/util/__tests__/https.js +301 -0
  136. package/lib/util/__tests__/navyrc.js +45 -0
  137. package/lib/util/__tests__/service-host.js +63 -5
  138. package/lib/util/__tests__/table.js +44 -0
  139. package/lib/util/docker-client.js +2 -10
  140. package/lib/util/exec-async.js +0 -4
  141. package/lib/util/external-ip.js +8 -12
  142. package/lib/util/fs.js +1 -6
  143. package/lib/util/get-lan-ip.js +0 -5
  144. package/lib/util/has-update.js +2 -14
  145. package/lib/util/https.js +11 -55
  146. package/lib/util/navyrc.js +0 -5
  147. package/lib/util/service-host.js +0 -17
  148. package/lib/util/table.js +0 -6
  149. package/package.json +14 -13
@@ -0,0 +1,75 @@
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 _filesystem = _interopRequireDefault(require("../config-providers/filesystem"));
7
+ var _npm = _interopRequireDefault(require("../config-providers/npm"));
8
+ var _configProvider = require("../config-provider");
9
+ /* eslint-env mocha */
10
+
11
+ describe('config-provider', function () {
12
+ let sandbox;
13
+ beforeEach(function () {
14
+ sandbox = _sinon.default.createSandbox();
15
+ });
16
+ afterEach(function () {
17
+ sandbox.restore();
18
+ });
19
+ describe('resolveConfigProviderFromName', function () {
20
+ it('should return the FileSystem provider for "filesystem"', function () {
21
+ (0, _chai.expect)((0, _configProvider.resolveConfigProviderFromName)('filesystem')).to.equal(_filesystem.default);
22
+ });
23
+ it('should return the NPM provider for "npm"', function () {
24
+ (0, _chai.expect)((0, _configProvider.resolveConfigProviderFromName)('npm')).to.equal(_npm.default);
25
+ });
26
+ it('should return null for unknown provider names', function () {
27
+ (0, _chai.expect)((0, _configProvider.resolveConfigProviderFromName)('git')).to.equal(null);
28
+ });
29
+ });
30
+ describe('getImportCommandLineOptions', function () {
31
+ it('should return the concatenation of every provider\'s importCliOptions', function () {
32
+ const options = (0, _configProvider.getImportCommandLineOptions)();
33
+ (0, _chai.expect)(options).to.be.an('array');
34
+ (0, _chai.expect)(options).to.eql([..._npm.default.importCliOptions, ..._filesystem.default.importCliOptions]);
35
+ });
36
+ });
37
+ describe('getImportOptionsForCLI', function () {
38
+ it('should return options from the first provider that returns a non-null value', async function () {
39
+ const npmStub = sandbox.stub(_npm.default, 'getImportOptionsForCLI').resolves(null);
40
+ const fsResult = {
41
+ configProvider: 'filesystem'
42
+ };
43
+ const fsStub = sandbox.stub(_filesystem.default, 'getImportOptionsForCLI').resolves(fsResult);
44
+ const result = await (0, _configProvider.getImportOptionsForCLI)({
45
+ path: '/tmp'
46
+ });
47
+ (0, _chai.expect)(result).to.equal(fsResult);
48
+ (0, _chai.expect)(npmStub.calledOnce).to.equal(true);
49
+ (0, _chai.expect)(fsStub.calledOnce).to.equal(true);
50
+ });
51
+ it('should not call subsequent providers once one returns options', async function () {
52
+ const npmResult = {
53
+ configProvider: 'npm'
54
+ };
55
+ const npmStub = sandbox.stub(_npm.default, 'getImportOptionsForCLI').resolves(npmResult);
56
+ const fsStub = sandbox.stub(_filesystem.default, 'getImportOptionsForCLI').resolves(null);
57
+ const result = await (0, _configProvider.getImportOptionsForCLI)({});
58
+ (0, _chai.expect)(result).to.equal(npmResult);
59
+ (0, _chai.expect)(npmStub.calledOnce).to.equal(true);
60
+ (0, _chai.expect)(fsStub.called).to.equal(false);
61
+ });
62
+ it('should throw an invariant violation when no provider matches', async function () {
63
+ sandbox.stub(_npm.default, 'getImportOptionsForCLI').resolves(null);
64
+ sandbox.stub(_filesystem.default, 'getImportOptionsForCLI').resolves(null);
65
+ let caught;
66
+ try {
67
+ await (0, _configProvider.getImportOptionsForCLI)({});
68
+ } catch (err) {
69
+ caught = err;
70
+ }
71
+ (0, _chai.expect)(caught).to.be.an('error');
72
+ (0, _chai.expect)(caught.message).to.match(/CLI_IMPORT_RESOLVE_OPTIONS_ERR/);
73
+ });
74
+ });
75
+ });
@@ -0,0 +1,130 @@
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 _path = _interopRequireDefault(require("path"));
7
+ var _fs = _interopRequireWildcard(require("fs"));
8
+ var _config = require("../config");
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
+ async function clearConfigCache(sandbox) {
13
+ const mkdirRestore = sandbox.stub(_fs.promises, 'mkdir').resolves();
14
+ const writeRestore = sandbox.stub(_fs.promises, 'writeFile').resolves();
15
+ await (0, _config.setConfig)(null);
16
+ mkdirRestore.restore();
17
+ writeRestore.restore();
18
+ }
19
+ describe('config', function () {
20
+ let sandbox;
21
+ let originalHome;
22
+ beforeEach(async function () {
23
+ sandbox = _sinon.default.createSandbox();
24
+ originalHome = process.env.HOME;
25
+ process.env.HOME = '/home/test-user';
26
+ await clearConfigCache(sandbox);
27
+ });
28
+ afterEach(function () {
29
+ sandbox.restore();
30
+ if (originalHome === undefined) {
31
+ delete process.env.HOME;
32
+ } else {
33
+ process.env.HOME = originalHome;
34
+ }
35
+ });
36
+ describe('getConfigDir', function () {
37
+ it('should join $HOME with .navy', function () {
38
+ (0, _chai.expect)((0, _config.getConfigDir)()).to.equal(_path.default.join('/home/test-user', '.navy'));
39
+ });
40
+ it('should throw when HOME is not set', function () {
41
+ delete process.env.HOME;
42
+ (0, _chai.expect)(() => (0, _config.getConfigDir)()).to.throw(/NO_HOME_DIRECTORY/);
43
+ });
44
+ });
45
+ describe('getConfigPath', function () {
46
+ it('should return <configDir>/config.json', function () {
47
+ (0, _chai.expect)((0, _config.getConfigPath)()).to.equal(_path.default.join('/home/test-user', '.navy', 'config.json'));
48
+ });
49
+ });
50
+ describe('DEFAULT_TLS_ROOT_CA_DIR', function () {
51
+ it('should be exported as a string referencing tls-root-ca', function () {
52
+ (0, _chai.expect)(_config.DEFAULT_TLS_ROOT_CA_DIR).to.be.a('string');
53
+ (0, _chai.expect)(_config.DEFAULT_TLS_ROOT_CA_DIR).to.contain('tls-root-ca');
54
+ });
55
+ });
56
+ describe('getConfig', function () {
57
+ it('should read the config file from disk and parse it as JSON', function () {
58
+ const onDisk = {
59
+ defaultNavy: 'mine',
60
+ externalIP: '10.0.0.1',
61
+ tlsRootCaDir: '/tmp/ca'
62
+ };
63
+ sandbox.stub(_fs.default, 'readFileSync').returns(JSON.stringify(onDisk));
64
+ (0, _chai.expect)((0, _config.getConfig)()).to.eql(onDisk);
65
+ });
66
+ it('should return the cached config on subsequent calls', function () {
67
+ const onDisk = {
68
+ defaultNavy: 'mine'
69
+ };
70
+ const readStub = sandbox.stub(_fs.default, 'readFileSync').returns(JSON.stringify(onDisk));
71
+ (0, _config.getConfig)();
72
+ (0, _config.getConfig)();
73
+ (0, _config.getConfig)();
74
+ (0, _chai.expect)(readStub.callCount).to.equal(1);
75
+ });
76
+ it('should fall back to default config when reading the file fails', function () {
77
+ sandbox.stub(_fs.default, 'readFileSync').throws(new Error('ENOENT'));
78
+ const cfg = (0, _config.getConfig)();
79
+ (0, _chai.expect)(cfg).to.have.property('defaultNavy', 'dev');
80
+ (0, _chai.expect)(cfg).to.have.property('externalIP', null);
81
+ (0, _chai.expect)(cfg).to.have.property('tlsRootCaDir').that.is.a('string');
82
+ });
83
+ });
84
+ describe('setConfig', function () {
85
+ it('should write the provided config to the config file', async function () {
86
+ const mkdirStub = sandbox.stub(_fs.promises, 'mkdir').resolves();
87
+ const writeStub = sandbox.stub(_fs.promises, 'writeFile').resolves();
88
+ await (0, _config.setConfig)({
89
+ defaultNavy: 'env-1'
90
+ });
91
+ (0, _chai.expect)(mkdirStub.calledOnce).to.equal(true);
92
+ (0, _chai.expect)(mkdirStub.firstCall.args[0]).to.equal(_path.default.join('/home/test-user', '.navy'));
93
+ (0, _chai.expect)(mkdirStub.firstCall.args[1]).to.eql({
94
+ recursive: true
95
+ });
96
+ (0, _chai.expect)(writeStub.calledOnce).to.equal(true);
97
+ (0, _chai.expect)(writeStub.firstCall.args[0]).to.equal(_path.default.join('/home/test-user', '.navy', 'config.json'));
98
+ (0, _chai.expect)(JSON.parse(writeStub.firstCall.args[1])).to.eql({
99
+ defaultNavy: 'env-1'
100
+ });
101
+ });
102
+ it('should write the default config when called with null', async function () {
103
+ sandbox.stub(_fs.promises, 'mkdir').resolves();
104
+ const writeStub = sandbox.stub(_fs.promises, 'writeFile').resolves();
105
+ await (0, _config.setConfig)(null);
106
+ const written = JSON.parse(writeStub.firstCall.args[1]);
107
+ (0, _chai.expect)(written).to.have.property('defaultNavy', 'dev');
108
+ });
109
+ it('should invalidate the cached config so the next getConfig re-reads', async function () {
110
+ const readStub = sandbox.stub(_fs.default, 'readFileSync').returns(JSON.stringify({
111
+ defaultNavy: 'one'
112
+ }));
113
+ (0, _config.getConfig)();
114
+ (0, _chai.expect)(readStub.callCount).to.equal(1);
115
+ sandbox.stub(_fs.promises, 'mkdir').resolves();
116
+ sandbox.stub(_fs.promises, 'writeFile').resolves();
117
+ await (0, _config.setConfig)({
118
+ defaultNavy: 'two'
119
+ });
120
+ readStub.returns(JSON.stringify({
121
+ defaultNavy: 'two'
122
+ }));
123
+ const cfg = (0, _config.getConfig)();
124
+ (0, _chai.expect)(readStub.callCount).to.equal(2);
125
+ (0, _chai.expect)(cfg).to.eql({
126
+ defaultNavy: 'two'
127
+ });
128
+ });
129
+ });
130
+ });
@@ -0,0 +1,148 @@
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 _cliSpinners = require("cli-spinners");
7
+ var _driverLogging = require("../driver-logging");
8
+ /* eslint-env mocha */
9
+
10
+ describe('driver-logging', function () {
11
+ let sandbox;
12
+ let clock;
13
+ let stdoutWrite;
14
+ let cursorTo;
15
+ let moveCursor;
16
+ let consoleLog;
17
+ let originalIsTTY;
18
+ let originalCursorTo;
19
+ let originalMoveCursor;
20
+ beforeEach(function () {
21
+ sandbox = _sinon.default.createSandbox();
22
+ clock = sandbox.useFakeTimers();
23
+ stdoutWrite = sandbox.stub(process.stdout, 'write').returns(true);
24
+ originalCursorTo = process.stdout.cursorTo;
25
+ originalMoveCursor = process.stdout.moveCursor;
26
+ process.stdout.cursorTo = function () {};
27
+ process.stdout.moveCursor = function () {};
28
+ cursorTo = sandbox.stub(process.stdout, 'cursorTo');
29
+ moveCursor = sandbox.stub(process.stdout, 'moveCursor');
30
+ consoleLog = sandbox.stub(console, 'log');
31
+ originalIsTTY = process.stdout.isTTY;
32
+ process.stdout.isTTY = true;
33
+ });
34
+ afterEach(function () {
35
+ if ((0, _driverLogging.isDriverLogging)()) {
36
+ (0, _driverLogging.stopDriverLogging)({
37
+ success: true
38
+ });
39
+ }
40
+ process.stdout.isTTY = originalIsTTY;
41
+ sandbox.restore();
42
+ if (originalCursorTo === undefined) {
43
+ delete process.stdout.cursorTo;
44
+ } else {
45
+ process.stdout.cursorTo = originalCursorTo;
46
+ }
47
+ if (originalMoveCursor === undefined) {
48
+ delete process.stdout.moveCursor;
49
+ } else {
50
+ process.stdout.moveCursor = originalMoveCursor;
51
+ }
52
+ });
53
+ describe('startDriverLogging / isDriverLogging', function () {
54
+ it('should mark logging as active and write the initial spinner frame', function () {
55
+ (0, _chai.expect)((0, _driverLogging.isDriverLogging)()).to.equal(false);
56
+ (0, _driverLogging.startDriverLogging)('Doing thing');
57
+ (0, _chai.expect)((0, _driverLogging.isDriverLogging)()).to.equal(true);
58
+ (0, _chai.expect)(stdoutWrite.called).to.equal(true);
59
+ const written = stdoutWrite.getCalls().map(c => c.args[0]).join('');
60
+ (0, _chai.expect)(written).to.contain('Doing thing');
61
+ });
62
+ it('should advance the spinner frame on each interval tick', function () {
63
+ (0, _driverLogging.startDriverLogging)('Working');
64
+ const writesBefore = stdoutWrite.callCount;
65
+ clock.tick(_cliSpinners.dots.interval);
66
+ (0, _chai.expect)(stdoutWrite.callCount).to.be.greaterThan(writesBefore);
67
+ });
68
+ it('should wrap the spinner frame index back to 0 after exhausting all frames', function () {
69
+ (0, _driverLogging.startDriverLogging)('Wrap test');
70
+ clock.tick(_cliSpinners.dots.interval * (_cliSpinners.dots.frames.length + 1));
71
+ (0, _chai.expect)((0, _driverLogging.isDriverLogging)()).to.equal(true);
72
+ });
73
+ });
74
+ describe('stopDriverLogging', function () {
75
+ it('should clear the logging state and emit a final success line', function () {
76
+ (0, _driverLogging.startDriverLogging)('Working');
77
+ (0, _driverLogging.stopDriverLogging)({
78
+ success: true
79
+ });
80
+ (0, _chai.expect)((0, _driverLogging.isDriverLogging)()).to.equal(false);
81
+ });
82
+ it('should default success to true when not provided', function () {
83
+ (0, _driverLogging.startDriverLogging)('Working');
84
+ (0, _driverLogging.stopDriverLogging)();
85
+ (0, _chai.expect)((0, _driverLogging.isDriverLogging)()).to.equal(false);
86
+ });
87
+ it('should mark a failure when success is false', function () {
88
+ (0, _driverLogging.startDriverLogging)('Working');
89
+ (0, _driverLogging.stopDriverLogging)({
90
+ success: false
91
+ });
92
+ (0, _chai.expect)((0, _driverLogging.isDriverLogging)()).to.equal(false);
93
+ });
94
+ it('should be a no-op if logging was never started', function () {
95
+ (0, _chai.expect)((0, _driverLogging.isDriverLogging)()).to.equal(false);
96
+ (0, _driverLogging.stopDriverLogging)({
97
+ success: true
98
+ });
99
+ (0, _chai.expect)(stdoutWrite.called).to.equal(false);
100
+ (0, _chai.expect)(cursorTo.called).to.equal(false);
101
+ (0, _chai.expect)(moveCursor.called).to.equal(false);
102
+ });
103
+ });
104
+ describe('non-TTY behaviour', function () {
105
+ beforeEach(function () {
106
+ process.stdout.isTTY = false;
107
+ });
108
+ it('should print a SUCCESS line via console.log when stopping with success', function () {
109
+ (0, _driverLogging.startDriverLogging)('Working');
110
+ (0, _driverLogging.stopDriverLogging)({
111
+ success: true
112
+ });
113
+ const messages = consoleLog.getCalls().map(c => c.args.join(' '));
114
+ const success = messages.find(m => m.includes('SUCCESS'));
115
+ (0, _chai.expect)(success).to.be.a('string');
116
+ });
117
+ it('should print a FAILURE line via console.log when stopping with success=false', function () {
118
+ (0, _driverLogging.startDriverLogging)('Working');
119
+ (0, _driverLogging.stopDriverLogging)({
120
+ success: false
121
+ });
122
+ const messages = consoleLog.getCalls().map(c => c.args.join(' '));
123
+ const failure = messages.find(m => m.includes('FAILURE'));
124
+ (0, _chai.expect)(failure).to.be.a('string');
125
+ });
126
+ it('should not print anything during ongoing spinner ticks while non-TTY', function () {
127
+ (0, _driverLogging.startDriverLogging)('Working');
128
+ const callsAtStart = consoleLog.callCount;
129
+ clock.tick(_cliSpinners.dots.interval * 3);
130
+ (0, _chai.expect)(consoleLog.callCount).to.equal(callsAtStart);
131
+ });
132
+ });
133
+ describe('log', function () {
134
+ it('should write the dimmed message to stdout while logging is active', function () {
135
+ (0, _driverLogging.startDriverLogging)('Active');
136
+ stdoutWrite.resetHistory();
137
+ (0, _driverLogging.log)('hello');
138
+ (0, _chai.expect)(stdoutWrite.calledOnce).to.equal(true);
139
+ (0, _chai.expect)(stdoutWrite.firstCall.args[0]).to.contain('hello');
140
+ });
141
+ it('should be a no-op when logging is not active', function () {
142
+ (0, _chai.expect)((0, _driverLogging.isDriverLogging)()).to.equal(false);
143
+ stdoutWrite.resetHistory();
144
+ (0, _driverLogging.log)('ignored');
145
+ (0, _chai.expect)(stdoutWrite.called).to.equal(false);
146
+ });
147
+ });
148
+ });
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ var _chai = require("chai");
5
+ var _driver = require("../driver");
6
+ var _dockerCompose = _interopRequireDefault(require("../drivers/docker-compose"));
7
+ /* eslint-env mocha */
8
+
9
+ describe('driver', function () {
10
+ describe('resolveDriverFromName', function () {
11
+ it('should return the docker-compose driver factory when given "docker-compose"', function () {
12
+ (0, _chai.expect)((0, _driver.resolveDriverFromName)('docker-compose')).to.equal(_dockerCompose.default);
13
+ });
14
+ it('should return null for an unknown driver name', function () {
15
+ (0, _chai.expect)((0, _driver.resolveDriverFromName)('podman')).to.equal(null);
16
+ (0, _chai.expect)((0, _driver.resolveDriverFromName)('')).to.equal(null);
17
+ });
18
+ });
19
+ });
@@ -0,0 +1,49 @@
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 _errors = require("../errors");
7
+ /* eslint-env mocha */
8
+
9
+ describe('errors', function () {
10
+ describe('NavyError', function () {
11
+ it('should expose the message passed to the constructor', function () {
12
+ const err = new _errors.NavyError('something went wrong');
13
+ (0, _chai.expect)(err.message).to.equal('something went wrong');
14
+ });
15
+ it('should print a red ERROR banner followed by the message and blank lines via prettyPrint', function () {
16
+ const log = _sinon.default.stub(console, 'log');
17
+ try {
18
+ new _errors.NavyError('boom').prettyPrint();
19
+ } finally {
20
+ log.restore();
21
+ }
22
+ (0, _chai.expect)(log.callCount).to.equal(5);
23
+ (0, _chai.expect)(log.firstCall.args).to.eql([]);
24
+ (0, _chai.expect)(log.secondCall.args[0]).to.contain('ERROR');
25
+ (0, _chai.expect)(log.thirdCall.args).to.eql([]);
26
+ (0, _chai.expect)(log.getCall(3).args[0]).to.equal(' boom');
27
+ (0, _chai.expect)(log.getCall(4).args).to.eql([]);
28
+ });
29
+ });
30
+ describe('NavyNotInitialisedError', function () {
31
+ it('should be a NavyError that includes the navy name in the message', function () {
32
+ const err = new _errors.NavyNotInitialisedError('myenv');
33
+ (0, _chai.expect)(err).to.be.instanceof(_errors.NavyError);
34
+ (0, _chai.expect)(err.message).to.equal('Navy "myenv" not imported');
35
+ });
36
+ it('should call the parent prettyPrint and add a hint about navy import', function () {
37
+ const log = _sinon.default.stub(console, 'log');
38
+ try {
39
+ new _errors.NavyNotInitialisedError('foo').prettyPrint();
40
+ } finally {
41
+ log.restore();
42
+ }
43
+ const messages = log.getCalls().map(call => call.args[0] || '');
44
+ const hint = messages.find(m => typeof m === 'string' && m.includes('navy import'));
45
+ (0, _chai.expect)(hint).to.be.a('string');
46
+ (0, _chai.expect)(hint).to.contain('imported the navy');
47
+ });
48
+ });
49
+ });
@@ -0,0 +1,214 @@
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 _os = _interopRequireDefault(require("os"));
7
+ var _path = _interopRequireDefault(require("path"));
8
+ var _jsYaml = _interopRequireDefault(require("js-yaml"));
9
+ var _fs = _interopRequireDefault(require("fs"));
10
+ var _dockerClient = _interopRequireDefault(require("../util/docker-client"));
11
+ var httpsModule = _interopRequireWildcard(require("../util/https"));
12
+ var execAsyncModule = _interopRequireWildcard(require("../util/exec-async"));
13
+ var driverLogging = _interopRequireWildcard(require("../driver-logging"));
14
+ var navyModule = _interopRequireWildcard(require("../navy"));
15
+ var _httpProxy = require("../http-proxy");
16
+ 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); }
17
+ /* eslint-env mocha */
18
+
19
+ describe('resolveProxyImage', function () {
20
+ afterEach(function () {
21
+ delete process.env.NAVY_HTTP_PROXY_IMAGE;
22
+ });
23
+ it('should return the default image when no env var or navyFile config is provided', function () {
24
+ (0, _chai.expect)((0, _httpProxy.resolveProxyImage)()).to.equal('navycloud/navy-proxy');
25
+ (0, _chai.expect)((0, _httpProxy.resolveProxyImage)(null)).to.equal('navycloud/navy-proxy');
26
+ (0, _chai.expect)((0, _httpProxy.resolveProxyImage)(undefined)).to.equal('navycloud/navy-proxy');
27
+ });
28
+ it('should return the default image when navyFile has no httpProxyImage', function () {
29
+ (0, _chai.expect)((0, _httpProxy.resolveProxyImage)({})).to.equal('navycloud/navy-proxy');
30
+ (0, _chai.expect)((0, _httpProxy.resolveProxyImage)({
31
+ plugins: []
32
+ })).to.equal('navycloud/navy-proxy');
33
+ });
34
+ it('should use httpProxyImage from navyFile when set', function () {
35
+ const navyFile = {
36
+ httpProxyImage: 'myregistry/custom-proxy:latest'
37
+ };
38
+ (0, _chai.expect)((0, _httpProxy.resolveProxyImage)(navyFile)).to.equal('myregistry/custom-proxy:latest');
39
+ });
40
+ it('should use NAVY_HTTP_PROXY_IMAGE env var when set', function () {
41
+ process.env.NAVY_HTTP_PROXY_IMAGE = 'envregistry/env-proxy:v2';
42
+ (0, _chai.expect)((0, _httpProxy.resolveProxyImage)()).to.equal('envregistry/env-proxy:v2');
43
+ });
44
+ it('should give NAVY_HTTP_PROXY_IMAGE env var precedence over navyFile httpProxyImage', function () {
45
+ process.env.NAVY_HTTP_PROXY_IMAGE = 'envregistry/env-proxy:v2';
46
+ const navyFile = {
47
+ httpProxyImage: 'myregistry/custom-proxy:latest'
48
+ };
49
+ (0, _chai.expect)((0, _httpProxy.resolveProxyImage)(navyFile)).to.equal('envregistry/env-proxy:v2');
50
+ });
51
+ it('should give NAVY_HTTP_PROXY_IMAGE env var precedence over default', function () {
52
+ process.env.NAVY_HTTP_PROXY_IMAGE = 'override/image:tag';
53
+ (0, _chai.expect)((0, _httpProxy.resolveProxyImage)(null)).to.equal('override/image:tag');
54
+ });
55
+ it('should fall back to default when httpProxyImage is an empty string', function () {
56
+ (0, _chai.expect)((0, _httpProxy.resolveProxyImage)({
57
+ httpProxyImage: ''
58
+ })).to.equal('navycloud/navy-proxy');
59
+ });
60
+ it('should fall back to default when NAVY_HTTP_PROXY_IMAGE is an empty string', function () {
61
+ process.env.NAVY_HTTP_PROXY_IMAGE = '';
62
+ (0, _chai.expect)((0, _httpProxy.resolveProxyImage)()).to.equal('navycloud/navy-proxy');
63
+ });
64
+ });
65
+ describe('resolveDockerSocketPath', function () {
66
+ let originalDockerHost;
67
+ beforeEach(function () {
68
+ originalDockerHost = process.env.DOCKER_HOST;
69
+ delete process.env.DOCKER_HOST;
70
+ });
71
+ afterEach(function () {
72
+ if (originalDockerHost === undefined) {
73
+ delete process.env.DOCKER_HOST;
74
+ } else {
75
+ process.env.DOCKER_HOST = originalDockerHost;
76
+ }
77
+ });
78
+ it('should default to /var/run/docker.sock when DOCKER_HOST is not set', function () {
79
+ (0, _chai.expect)((0, _httpProxy.resolveDockerSocketPath)()).to.equal('/var/run/docker.sock');
80
+ });
81
+ it('should default to /var/run/docker.sock when DOCKER_HOST is empty', function () {
82
+ process.env.DOCKER_HOST = '';
83
+ (0, _chai.expect)((0, _httpProxy.resolveDockerSocketPath)()).to.equal('/var/run/docker.sock');
84
+ });
85
+ it('should extract the socket path when DOCKER_HOST uses the unix:// scheme', function () {
86
+ process.env.DOCKER_HOST = 'unix:///home/runner/setup-docker-action-abc/docker.sock';
87
+ (0, _chai.expect)((0, _httpProxy.resolveDockerSocketPath)()).to.equal('/home/runner/setup-docker-action-abc/docker.sock');
88
+ });
89
+ it('should fall back to default when DOCKER_HOST is unix:// with no path', function () {
90
+ process.env.DOCKER_HOST = 'unix://';
91
+ (0, _chai.expect)((0, _httpProxy.resolveDockerSocketPath)()).to.equal('/var/run/docker.sock');
92
+ });
93
+ it('should fall back to default when DOCKER_HOST uses tcp:// scheme', function () {
94
+ process.env.DOCKER_HOST = 'tcp://localhost:2375';
95
+ (0, _chai.expect)((0, _httpProxy.resolveDockerSocketPath)()).to.equal('/var/run/docker.sock');
96
+ });
97
+ });
98
+ describe('reconfigureHTTPProxy', function () {
99
+ let sandbox;
100
+ let writeFileSyncStub;
101
+ let existsSyncStub;
102
+ let listNetworksStub;
103
+ let execStub;
104
+ let originalDockerHost;
105
+ const composeFile = _path.default.join(_os.default.tmpdir(), 'navyinternaldockercompose.yml');
106
+ beforeEach(function () {
107
+ originalDockerHost = process.env.DOCKER_HOST;
108
+ delete process.env.DOCKER_HOST;
109
+ sandbox = _sinon.default.createSandbox();
110
+ listNetworksStub = sandbox.stub(_dockerClient.default, 'listNetworks');
111
+ sandbox.stub(httpsModule, 'getCertsPath').resolves('');
112
+ sandbox.stub(driverLogging, 'log');
113
+ sandbox.stub(navyModule, 'getLaunchedNavyNames').resolves([]);
114
+ execStub = sandbox.stub(execAsyncModule, 'execAsync').resolves('');
115
+ writeFileSyncStub = sandbox.stub(_fs.default, 'writeFileSync');
116
+ existsSyncStub = sandbox.stub(_fs.default, 'existsSync').returns(false);
117
+ });
118
+ afterEach(function () {
119
+ sandbox.restore();
120
+ if (originalDockerHost === undefined) {
121
+ delete process.env.DOCKER_HOST;
122
+ } else {
123
+ process.env.DOCKER_HOST = originalDockerHost;
124
+ }
125
+ });
126
+ it('should default opts.navies via getLaunchedNavyNames when not supplied', async function () {
127
+ listNetworksStub.resolves([]);
128
+ navyModule.getLaunchedNavyNames.resolves(['navyA']);
129
+ await (0, _httpProxy.reconfigureHTTPProxy)();
130
+ (0, _chai.expect)(navyModule.getLaunchedNavyNames.calledOnce).to.equal(true);
131
+ });
132
+ it('should write a docker-compose config containing only matching docker-compose networks', async function () {
133
+ listNetworksStub.resolves([{
134
+ Name: 'navyA_default'
135
+ }, {
136
+ Name: 'navyB_default'
137
+ }, {
138
+ Name: 'host'
139
+ }, {
140
+ Name: 'navyB_other'
141
+ }, {
142
+ Name: 'name-without-underscore'
143
+ }]);
144
+ await (0, _httpProxy.reconfigureHTTPProxy)({
145
+ navies: ['navyA']
146
+ });
147
+ (0, _chai.expect)(writeFileSyncStub.calledOnce).to.equal(true);
148
+ (0, _chai.expect)(writeFileSyncStub.firstCall.args[0]).to.equal(composeFile);
149
+ const written = _jsYaml.default.load(writeFileSyncStub.firstCall.args[1]);
150
+ (0, _chai.expect)(written.networks).to.have.property('navyA_default').that.eql({
151
+ external: true
152
+ });
153
+ (0, _chai.expect)(written.networks).to.not.have.property('navyB_default');
154
+ (0, _chai.expect)(written.networks).to.not.have.property('host');
155
+ (0, _chai.expect)(written.services['nginx-proxy'].image).to.equal('navycloud/navy-proxy');
156
+ (0, _chai.expect)(written.services['nginx-proxy'].ports).to.eql(['80:80']);
157
+ (0, _chai.expect)(written.services['nginx-proxy'].volumes[0]).to.equal('/var/run/docker.sock:/tmp/docker.sock:ro');
158
+ });
159
+ it('should mount certs and expose port 443 when a certs path is available', async function () {
160
+ httpsModule.getCertsPath.resolves('/certs');
161
+ listNetworksStub.resolves([]);
162
+ await (0, _httpProxy.reconfigureHTTPProxy)({
163
+ navies: []
164
+ });
165
+ const written = _jsYaml.default.load(writeFileSyncStub.firstCall.args[1]);
166
+ (0, _chai.expect)(written.services['nginx-proxy'].ports).to.eql(['80:80', '443:443']);
167
+ (0, _chai.expect)(written.services['nginx-proxy'].volumes).to.include('/certs:/etc/nginx/certs');
168
+ (0, _chai.expect)(written.services['nginx-proxy'].volumes).to.include('/certs:/etc/nginx/dhparam');
169
+ });
170
+ it('should pass the configured proxy image from navyFile through to the compose config', async function () {
171
+ listNetworksStub.resolves([]);
172
+ await (0, _httpProxy.reconfigureHTTPProxy)({
173
+ navies: [],
174
+ navyFile: {
175
+ httpProxyImage: 'custom/proxy:1'
176
+ }
177
+ });
178
+ const written = _jsYaml.default.load(writeFileSyncStub.firstCall.args[1]);
179
+ (0, _chai.expect)(written.services['nginx-proxy'].image).to.equal('custom/proxy:1');
180
+ });
181
+ it('should run docker compose up after writing the config', async function () {
182
+ listNetworksStub.resolves([]);
183
+ await (0, _httpProxy.reconfigureHTTPProxy)({
184
+ navies: []
185
+ });
186
+ const upCall = execStub.getCalls().find(c => Array.isArray(c.args[1]) && c.args[1].includes('up'));
187
+ // eslint-disable-next-line no-unused-expressions
188
+ (0, _chai.expect)(upCall).to.exist;
189
+ (0, _chai.expect)(upCall.args[0]).to.equal('docker compose');
190
+ (0, _chai.expect)(upCall.args[1]).to.eql(['-f', composeFile, '-p', 'navyinternal', 'up', '-d']);
191
+ });
192
+ it('should rm the existing nginx-proxy container before reconfiguring when restart=true and the file exists', async function () {
193
+ listNetworksStub.resolves([]);
194
+ existsSyncStub.withArgs(composeFile).returns(true);
195
+ await (0, _httpProxy.reconfigureHTTPProxy)({
196
+ navies: [],
197
+ restart: true
198
+ });
199
+ const rmCall = execStub.getCalls().find(c => Array.isArray(c.args[1]) && c.args[1].includes('rm'));
200
+ // eslint-disable-next-line no-unused-expressions
201
+ (0, _chai.expect)(rmCall).to.exist;
202
+ (0, _chai.expect)(rmCall.args[1]).to.eql(['-f', composeFile, '-p', 'navyinternal', 'rm', '-s', '-f', 'nginx-proxy']);
203
+ });
204
+ it('should skip the rm step when restart=true but no compose file exists yet', async function () {
205
+ listNetworksStub.resolves([]);
206
+ existsSyncStub.withArgs(composeFile).returns(false);
207
+ await (0, _httpProxy.reconfigureHTTPProxy)({
208
+ navies: [],
209
+ restart: true
210
+ });
211
+ const rmCall = execStub.getCalls().find(c => Array.isArray(c.args[1]) && c.args[1].includes('rm'));
212
+ (0, _chai.expect)(rmCall).to.equal(undefined);
213
+ });
214
+ });
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+
3
+ var _chai = require("chai");
4
+ var navyModule = _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('navy package entry point', function () {
9
+ it('should re-export the Navy class and navy lookup helpers', function () {
10
+ (0, _chai.expect)(navyModule).to.have.property('Navy').that.is.a('function');
11
+ (0, _chai.expect)(navyModule).to.have.property('getNavy').that.is.a('function');
12
+ (0, _chai.expect)(navyModule).to.have.property('getLaunchedNavies').that.is.a('function');
13
+ (0, _chai.expect)(navyModule).to.have.property('getLaunchedNavyNames').that.is.a('function');
14
+ });
15
+ it('should expose the Service module under Service', function () {
16
+ (0, _chai.expect)(navyModule).to.have.property('Service').that.is.an('object');
17
+ (0, _chai.expect)(navyModule.Service).to.have.property('Status').that.is.an('object');
18
+ });
19
+ it('should re-export NavyError', function () {
20
+ (0, _chai.expect)(navyModule).to.have.property('NavyError').that.is.a('function');
21
+ });
22
+ it('should re-export middlewareHelpers', function () {
23
+ (0, _chai.expect)(navyModule).to.have.property('middlewareHelpers').that.is.an('object');
24
+ });
25
+ });