@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abgov/nx-oc",
3
- "version": "12.3.0-beta.1",
3
+ "version": "12.4.0",
4
4
  "license": "Apache-2.0",
5
5
  "main": "src/index.js",
6
6
  "description": "Government of Alberta - Nx plugin for OpenShift.",
@@ -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
- const { success } = (0, oc_utils_1.runOcCommand)('project', []);
18
- if (success) {
19
- applyOcResources(host);
17
+ try {
18
+ (0, oc_utils_1.ensureOcLogin)();
20
19
  }
21
- else {
22
- console.log(`Use oc login then run 'nx g @abgov/nx-oc:apply-infra'`);
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,4BAOC;;AA7BD,mDAAoD;AAEpD,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,MAAM,EAAE,OAAO,EAAE,GAAG,IAAA,uBAAY,EAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QAChD,IAAI,OAAO,EAAE,CAAC;YACZ,gBAAgB,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,uDAAuD,CAAC,CAAC;QACvE,CAAC;IACH,CAAC;CAAA"}
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(mockedRunOcCommand.mock.calls.length).toBe(3);
25
- expect(mockedRunOcCommand.mock.calls[0][0]).toBe('project');
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
- expect(mockedRunOcCommand.mock.calls[2][0]).toBe('apply');
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
  });
@@ -2,3 +2,4 @@ export declare function runOcCommand(command: 'project' | 'start-build' | 'proce
2
2
  success: boolean;
3
3
  stdout?: Buffer;
4
4
  };
5
+ export declare function ensureOcLogin(): void;
@@ -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;AAnBD,iDAA6C;AAE7C,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"}
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
+ });