@abgov/nx-oc 12.3.0-beta.1 → 12.4.0
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/package.json +1 -1
- package/src/generators/apply-infra/apply-infra.js +6 -5
- package/src/generators/apply-infra/apply-infra.js.map +1 -1
- package/src/generators/apply-infra/apply-infra.spec.ts +17 -4
- package/src/utils/oc-utils.d.ts +1 -0
- package/src/utils/oc-utils.js +32 -0
- package/src/utils/oc-utils.js.map +1 -1
- package/src/utils/oc-utils.spec.ts +67 -2
package/package.json
CHANGED
|
@@ -14,13 +14,14 @@ function applyOcResources(host) {
|
|
|
14
14
|
}
|
|
15
15
|
function default_1(host) {
|
|
16
16
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
applyOcResources(host);
|
|
17
|
+
try {
|
|
18
|
+
(0, oc_utils_1.ensureOcLogin)();
|
|
20
19
|
}
|
|
21
|
-
|
|
22
|
-
console.log(
|
|
20
|
+
catch (e) {
|
|
21
|
+
console.log(e instanceof Error ? e.message : String(e));
|
|
22
|
+
return;
|
|
23
23
|
}
|
|
24
|
+
applyOcResources(host);
|
|
24
25
|
});
|
|
25
26
|
}
|
|
26
27
|
//# sourceMappingURL=apply-infra.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apply-infra.js","sourceRoot":"","sources":["../../../../../../packages/nx-oc/src/generators/apply-infra/apply-infra.ts"],"names":[],"mappings":";;AAuBA,
|
|
1
|
+
{"version":3,"file":"apply-infra.js","sourceRoot":"","sources":["../../../../../../packages/nx-oc/src/generators/apply-infra/apply-infra.ts"],"names":[],"mappings":";;AAuBA,4BAQC;;AA9BD,mDAAmE;AAEnE,SAAS,gBAAgB,CAAC,IAAU;IAClC,MAAM,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,IAAA,uBAAY,EACpE,OAAO,EACP,EAAE,EACF,IAAI,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAC9C,CAAC;IACF,OAAO,CAAC,GAAG,CAAC,WAAW,aAAX,WAAW,uBAAX,WAAW,CAAE,QAAQ,EAAE,CAAC,CAAC;IAErC,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,IAAA,uBAAY,EAC1D,OAAO,EACP,EAAE,EACF,IAAI,CAAC,IAAI,CAAC,6BAA6B,CAAC,CACzC,CAAC;IACF,OAAO,CAAC,GAAG,CAAC,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,QAAQ,EAAE,CAAC,CAAC;IAEhC,IAAI,CAAC,eAAe,IAAI,CAAC,UAAU,EAAE,CAAC;QACpC,OAAO,CAAC,GAAG,CAAC,kDAAkD,CAAC,CAAC;IAClE,CAAC;AACH,CAAC;AAED,mBAA+B,IAAU;;QACvC,IAAI,CAAC;YACH,IAAA,wBAAa,GAAE,CAAC;QAClB,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,CAAC,GAAG,CAAC,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;YACxD,OAAO;QACT,CAAC;QACD,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;CAAA"}
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { createTree } from '@nx/devkit/testing';
|
|
2
2
|
import { mocked } from 'jest-mock';
|
|
3
3
|
import generator from './apply-infra';
|
|
4
|
-
import { runOcCommand } from '../../utils/oc-utils';
|
|
4
|
+
import { ensureOcLogin, runOcCommand } from '../../utils/oc-utils';
|
|
5
5
|
import { writeJson } from '@nx/devkit';
|
|
6
6
|
|
|
7
7
|
jest.mock('../../utils/oc-utils');
|
|
8
|
+
const mockedEnsureOcLogin = mocked(ensureOcLogin);
|
|
8
9
|
const mockedRunOcCommand = mocked(runOcCommand);
|
|
9
10
|
|
|
10
11
|
describe('Apply Infra Generator', () => {
|
|
11
12
|
beforeEach(() => {
|
|
13
|
+
mockedEnsureOcLogin.mockReset();
|
|
12
14
|
mockedRunOcCommand.mockReset();
|
|
13
15
|
});
|
|
14
16
|
|
|
@@ -21,9 +23,20 @@ describe('Apply Infra Generator', () => {
|
|
|
21
23
|
|
|
22
24
|
await generator(host);
|
|
23
25
|
|
|
24
|
-
expect(
|
|
25
|
-
expect(mockedRunOcCommand.mock.calls
|
|
26
|
+
expect(mockedEnsureOcLogin).toHaveBeenCalledTimes(1);
|
|
27
|
+
expect(mockedRunOcCommand.mock.calls.length).toBe(2);
|
|
28
|
+
expect(mockedRunOcCommand.mock.calls[0][0]).toBe('apply');
|
|
26
29
|
expect(mockedRunOcCommand.mock.calls[1][0]).toBe('apply');
|
|
27
|
-
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('logs login error and exits cleanly without running oc apply', async () => {
|
|
33
|
+
const host = createTree();
|
|
34
|
+
mockedEnsureOcLogin.mockImplementation(() => {
|
|
35
|
+
throw new Error('oc CLI is not installed or not on PATH.');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
await generator(host);
|
|
39
|
+
|
|
40
|
+
expect(mockedRunOcCommand).not.toHaveBeenCalled();
|
|
28
41
|
});
|
|
29
42
|
});
|
package/src/utils/oc-utils.d.ts
CHANGED
package/src/utils/oc-utils.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.runOcCommand = runOcCommand;
|
|
4
|
+
exports.ensureOcLogin = ensureOcLogin;
|
|
4
5
|
const child_process_1 = require("child_process");
|
|
5
6
|
function runOcCommand(command, params, input) {
|
|
6
7
|
const args = input
|
|
@@ -16,4 +17,35 @@ function runOcCommand(command, params, input) {
|
|
|
16
17
|
return { success: false };
|
|
17
18
|
}
|
|
18
19
|
}
|
|
20
|
+
function ensureOcLogin() {
|
|
21
|
+
try {
|
|
22
|
+
(0, child_process_1.execFileSync)('oc', ['version', '--client'], { stdio: 'pipe' });
|
|
23
|
+
}
|
|
24
|
+
catch (_a) {
|
|
25
|
+
throw new Error("oc CLI is not installed or not on PATH. Install it from https://mirror.openshift.com/pub/openshift-v4/clients/ocp/latest/ then re-run.");
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
(0, child_process_1.execFileSync)('oc', ['whoami'], { stdio: 'pipe' });
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
catch (_b) {
|
|
32
|
+
// not logged in — fall through to interactive login
|
|
33
|
+
}
|
|
34
|
+
let server = null;
|
|
35
|
+
try {
|
|
36
|
+
server =
|
|
37
|
+
(0, child_process_1.execFileSync)('oc', ['config', 'view', '--minify', '-o', 'jsonpath={.clusters[0].cluster.server}'], { stdio: 'pipe' })
|
|
38
|
+
.toString()
|
|
39
|
+
.trim() || null;
|
|
40
|
+
}
|
|
41
|
+
catch (_c) {
|
|
42
|
+
// no kubeconfig — oc login will prompt for server
|
|
43
|
+
}
|
|
44
|
+
console.log('Not logged in to OpenShift. Starting interactive login...');
|
|
45
|
+
const loginArgs = server ? ['login', server, '--web'] : ['login', '--web'];
|
|
46
|
+
const result = (0, child_process_1.spawnSync)('oc', loginArgs, { stdio: 'inherit' });
|
|
47
|
+
if (result.status !== 0) {
|
|
48
|
+
throw new Error("OpenShift login failed or was cancelled. Run 'oc login' manually then re-run the generator.");
|
|
49
|
+
}
|
|
50
|
+
}
|
|
19
51
|
//# sourceMappingURL=oc-utils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oc-utils.js","sourceRoot":"","sources":["../../../../../packages/nx-oc/src/utils/oc-utils.ts"],"names":[],"mappings":";;AAEA,oCAiBC;
|
|
1
|
+
{"version":3,"file":"oc-utils.js","sourceRoot":"","sources":["../../../../../packages/nx-oc/src/utils/oc-utils.ts"],"names":[],"mappings":";;AAEA,oCAiBC;AAED,sCAmCC;AAxDD,iDAAwD;AAExD,SAAgB,YAAY,CAC1B,OAAwD,EACxD,MAAgB,EAChB,KAAc;IAEd,MAAM,IAAI,GAAG,KAAK;QAChB,CAAC,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,MAAM,CAAC;QACjC,CAAC,CAAC,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,CAAC;IAEzB,IAAI,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,yBAAyB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACvD,MAAM,MAAM,GAAG,IAAA,4BAAY,EAAC,IAAI,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;QAClE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IACnC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,CAAC,GAAG,CAAC,iCAAiC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QAClE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC5B,CAAC;AACH,CAAC;AAED,SAAgB,aAAa;IAC3B,IAAI,CAAC;QACH,IAAA,4BAAY,EAAC,IAAI,EAAE,CAAC,SAAS,EAAE,UAAU,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IACjE,CAAC;IAAC,WAAM,CAAC;QACP,MAAM,IAAI,KAAK,CACb,wIAAwI,CACzI,CAAC;IACJ,CAAC;IAED,IAAI,CAAC;QACH,IAAA,4BAAY,EAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QAClD,OAAO;IACT,CAAC;IAAC,WAAM,CAAC;QACP,oDAAoD;IACtD,CAAC;IAED,IAAI,MAAM,GAAkB,IAAI,CAAC;IACjC,IAAI,CAAC;QACH,MAAM;YACJ,IAAA,4BAAY,EAAC,IAAI,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,wCAAwC,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;iBAClH,QAAQ,EAAE;iBACV,IAAI,EAAE,IAAI,IAAI,CAAC;IACtB,CAAC;IAAC,WAAM,CAAC;QACP,kDAAkD;IACpD,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,2DAA2D,CAAC,CAAC;IACzE,MAAM,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IAC3E,MAAM,MAAM,GAAG,IAAA,yBAAS,EAAC,IAAI,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;IAEhE,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CACb,6FAA6F,CAC9F,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import { execFileSync } from 'child_process';
|
|
1
|
+
import { execFileSync, spawnSync } from 'child_process';
|
|
2
2
|
import { mocked } from 'jest-mock';
|
|
3
|
-
import { runOcCommand } from './oc-utils';
|
|
3
|
+
import { ensureOcLogin, runOcCommand } from './oc-utils';
|
|
4
4
|
|
|
5
5
|
jest.mock('child_process');
|
|
6
6
|
const mockedExecFileSync = mocked(execFileSync);
|
|
7
|
+
const mockedSpawnSync = mocked(spawnSync);
|
|
8
|
+
|
|
9
|
+
const SPAWN_OK = { status: 0, pid: 1, output: [], stdout: Buffer.from(''), stderr: Buffer.from(''), signal: null };
|
|
10
|
+
const SPAWN_FAIL = { ...SPAWN_OK, status: 1 };
|
|
7
11
|
|
|
8
12
|
describe('runOcCommand', () => {
|
|
9
13
|
beforeEach(() => {
|
|
@@ -61,3 +65,64 @@ describe('runOcCommand', () => {
|
|
|
61
65
|
expect(result.stdout).toBeUndefined();
|
|
62
66
|
});
|
|
63
67
|
});
|
|
68
|
+
|
|
69
|
+
describe('ensureOcLogin', () => {
|
|
70
|
+
beforeEach(() => {
|
|
71
|
+
mockedExecFileSync.mockReset();
|
|
72
|
+
mockedSpawnSync.mockReset();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('returns without spawning login when already logged in', () => {
|
|
76
|
+
mockedExecFileSync.mockReturnValueOnce(Buffer.from('Client Version: 4.14.0')); // oc version --client
|
|
77
|
+
mockedExecFileSync.mockReturnValueOnce(Buffer.from('developer')); // oc whoami
|
|
78
|
+
|
|
79
|
+
ensureOcLogin();
|
|
80
|
+
|
|
81
|
+
expect(mockedSpawnSync).not.toHaveBeenCalled();
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('throws a clear error when oc is not installed', () => {
|
|
85
|
+
mockedExecFileSync.mockImplementationOnce(() => {
|
|
86
|
+
throw new Error('oc: command not found');
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
expect(() => ensureOcLogin()).toThrow('oc CLI is not installed');
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('spawns oc login with server and --web when kubeconfig has a current context', () => {
|
|
93
|
+
mockedExecFileSync.mockReturnValueOnce(Buffer.from('Client Version: 4.14.0')); // oc version --client
|
|
94
|
+
mockedExecFileSync.mockImplementationOnce(() => { throw new Error('not logged in'); }); // oc whoami
|
|
95
|
+
mockedExecFileSync.mockReturnValueOnce(Buffer.from('https://api.example.openshift.com:6443')); // oc config view
|
|
96
|
+
mockedSpawnSync.mockReturnValue(SPAWN_OK);
|
|
97
|
+
|
|
98
|
+
ensureOcLogin();
|
|
99
|
+
|
|
100
|
+
expect(mockedSpawnSync).toHaveBeenCalledWith(
|
|
101
|
+
'oc',
|
|
102
|
+
['login', 'https://api.example.openshift.com:6443', '--web'],
|
|
103
|
+
{ stdio: 'inherit' }
|
|
104
|
+
);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('spawns oc login with only --web when no kubeconfig exists', () => {
|
|
108
|
+
mockedExecFileSync.mockReturnValueOnce(Buffer.from('Client Version: 4.14.0')); // oc version --client
|
|
109
|
+
mockedExecFileSync.mockImplementationOnce(() => { throw new Error('not logged in'); }); // oc whoami
|
|
110
|
+
mockedExecFileSync.mockImplementationOnce(() => { throw new Error('no config'); }); // oc config view
|
|
111
|
+
|
|
112
|
+
mockedSpawnSync.mockReturnValue(SPAWN_OK);
|
|
113
|
+
|
|
114
|
+
ensureOcLogin();
|
|
115
|
+
|
|
116
|
+
expect(mockedSpawnSync).toHaveBeenCalledWith('oc', ['login', '--web'], { stdio: 'inherit' });
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('throws when login is cancelled or fails', () => {
|
|
120
|
+
mockedExecFileSync.mockReturnValueOnce(Buffer.from('Client Version: 4.14.0')); // oc version --client
|
|
121
|
+
mockedExecFileSync.mockImplementationOnce(() => { throw new Error('not logged in'); }); // oc whoami
|
|
122
|
+
mockedExecFileSync.mockImplementationOnce(() => { throw new Error('no config'); }); // oc config view
|
|
123
|
+
|
|
124
|
+
mockedSpawnSync.mockReturnValue(SPAWN_FAIL);
|
|
125
|
+
|
|
126
|
+
expect(() => ensureOcLogin()).toThrow('OpenShift login failed or was cancelled');
|
|
127
|
+
});
|
|
128
|
+
});
|