@rockcarver/frodo-cli 0.12.3 → 0.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/CHANGELOG.md CHANGED
@@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.12.4-0] - 2022-09-02
11
+
10
12
  ## [0.12.3] - 2022-09-01
11
13
 
12
14
  ### Fixed
@@ -450,7 +452,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
450
452
  - Fixed problem with adding connection profiles
451
453
  - Miscellaneous bug fixes
452
454
 
453
- [Unreleased]: https://github.com/rockcarver/frodo-cli/compare/v0.12.3...HEAD
455
+ [Unreleased]: https://github.com/rockcarver/frodo-cli/compare/v0.12.4-0...HEAD
456
+
457
+ [0.12.4-0]: https://github.com/rockcarver/frodo-cli/compare/v0.12.3...v0.12.4-0
454
458
 
455
459
  [0.12.3]: https://github.com/rockcarver/frodo-cli/compare/v0.12.3-1...v0.12.3
456
460
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rockcarver/frodo-cli",
3
- "version": "0.12.3",
3
+ "version": "0.12.4-0",
4
4
  "type": "module",
5
5
  "description": "A command line interface to manage ForgeRock Identity Cloud tenants, ForgeOps deployments, and classic deployments.",
6
6
  "keywords": [
@@ -85,12 +85,13 @@
85
85
  },
86
86
  "dependencies": {
87
87
  "@colors/colors": "^1.5.0",
88
- "@rockcarver/frodo-lib": "~0.12.1",
88
+ "@rockcarver/frodo-lib": "0.12.2-0",
89
89
  "cli-progress": "^3.11.2",
90
90
  "cli-table3": "^0.6.2",
91
91
  "commander": "^9.4.0",
92
92
  "nanospinner": "^1.1.0",
93
- "uuid": "^8.3.2"
93
+ "uuid": "^8.3.2",
94
+ "yesno": "^0.4.0"
94
95
  },
95
96
  "devDependencies": {
96
97
  "@babel/eslint-parser": "^7.18.9",
@@ -1,9 +1,17 @@
1
1
  import { Command, Option } from 'commander';
2
- import { Authenticate, Startup, state } from '@rockcarver/frodo-lib';
2
+ import {
3
+ Authenticate,
4
+ Startup,
5
+ ManagedObject,
6
+ state,
7
+ } from '@rockcarver/frodo-lib';
8
+ import yesno from 'yesno';
3
9
  import * as common from '../cmd_common.js';
10
+ import { createTable, printMessage } from '../../utils/Console.js';
4
11
 
5
12
  const { getTokens } = Authenticate;
6
13
  const { applyUpdates, checkForUpdates } = Startup;
14
+ const { resolveUserName } = ManagedObject;
7
15
 
8
16
  const program = new Command('frodo esv apply');
9
17
 
@@ -37,6 +45,12 @@ program
37
45
  'Verbose output during command execution. If specified, may or may not produce additional output.'
38
46
  ).default(false, 'off')
39
47
  )
48
+ .addOption(
49
+ new Option(
50
+ '--timeout <seconds>',
51
+ 'Specify a timeout in seconds how long the tool should wait for the apply command to finish. Only effective without --no-wait.'
52
+ ).default(600, '600 secs (10 mins)')
53
+ )
40
54
  .addOption(new Option('-y, --yes', 'Answer y/yes to all prompts.'))
41
55
  .action(
42
56
  // implement command logic inside action handler
@@ -48,15 +62,55 @@ program
48
62
  state.default.session.setDeploymentType(options.type);
49
63
  state.default.session.setAllowInsecureConnection(options.insecure);
50
64
  if (await getTokens()) {
51
- // check for updates only
52
- if (options.checkOnly) {
53
- console.log(`Checking for updates...`);
54
- await checkForUpdates();
65
+ const updates = await checkForUpdates();
66
+ const updatesTable = createTable([
67
+ 'Type',
68
+ 'Name',
69
+ 'Modified',
70
+ 'Modifier',
71
+ ]);
72
+ for (const secret of updates.secrets) {
73
+ if (!secret.loaded) {
74
+ updatesTable.push([
75
+ 'secret',
76
+ secret._id,
77
+ new Date(secret.lastChangeDate).toLocaleString(),
78
+ // eslint-disable-next-line no-await-in-loop
79
+ await resolveUserName('teammember', secret.lastChangedBy),
80
+ ]);
81
+ }
82
+ }
83
+ for (const variable of updates.variables) {
84
+ if (!variable.loaded) {
85
+ updatesTable.push([
86
+ 'variable',
87
+ variable._id,
88
+ new Date(variable.lastChangeDate).toLocaleString(),
89
+ // eslint-disable-next-line no-await-in-loop
90
+ await resolveUserName('teammember', variable.lastChangedBy),
91
+ ]);
92
+ }
93
+ }
94
+ if (updatesTable.length > 0) {
95
+ printMessage(updatesTable.toString(), 'data');
55
96
  }
56
- // apply updates
57
- else {
58
- console.log(`Applying updates...`);
59
- await applyUpdates(options.force, options.wait, options.yes);
97
+ if (!options.checkOnly) {
98
+ if (
99
+ updates.secrets?.length ||
100
+ updates.variables?.length ||
101
+ options.force
102
+ ) {
103
+ const ok =
104
+ options.yes ||
105
+ (await yesno({
106
+ question: `\nChanges may take up to 10 minutes to propagate, during which time you will not be able to make further updates.\n\nApply updates? (y|n):`,
107
+ }));
108
+ if (ok) {
109
+ if (!(await applyUpdates(options.wait, options.timeout * 1000))) {
110
+ process.exitCode = 1;
111
+ }
112
+ }
113
+ }
60
114
  }
61
115
  }
62
116
  }
@@ -4,7 +4,7 @@ import { Authenticate, Journey, state } from '@rockcarver/frodo-lib';
4
4
  import * as common from '../cmd_common.js';
5
5
 
6
6
  const { getTokens } = Authenticate;
7
- const { listJourneys, getJourneyData, describeTree } = Journey;
7
+ const { listJourneys, exportTree, describeTree } = Journey;
8
8
 
9
9
  const program = new Command('frodo journey describe');
10
10
 
@@ -47,7 +47,6 @@ program
47
47
  state.default.session.setPassword(password);
48
48
  state.default.session.setDeploymentType(options.type);
49
49
  state.default.session.setAllowInsecureConnection(options.insecure);
50
- const treeDescription = [];
51
50
  // TODO: review checks for arguments
52
51
  if (typeof host === 'undefined' || typeof options.file !== 'undefined') {
53
52
  if (typeof options.file === 'undefined') {
@@ -61,7 +60,7 @@ program
61
60
  try {
62
61
  const data = fs.readFileSync(options.file, 'utf8');
63
62
  const journeyData = JSON.parse(data);
64
- treeDescription.push(describeTree(journeyData));
63
+ describeTree(journeyData);
65
64
  } catch (err) {
66
65
  console.log(err, 'error');
67
66
  }
@@ -74,36 +73,14 @@ program
74
73
  // createProgressBar(journeyList.length, '');
75
74
  for (const item of journeyList) {
76
75
  // eslint-disable-next-line no-await-in-loop
77
- const journeyData = await getJourneyData(item.name);
78
- treeDescription.push(describeTree(journeyData));
76
+ const journeyData = await exportTree(item.name);
77
+ describeTree(journeyData);
79
78
  // updateProgressBar(`Analyzing journey - ${item.name}`);
80
79
  }
81
80
  // stopProgressBar('Done');
82
81
  } else {
83
- const journeyData = await getJourneyData(options.journeyId);
84
- treeDescription.push(describeTree(journeyData));
85
- }
86
- }
87
- for (const item of treeDescription) {
88
- console.log(`\nJourney: ${item.treeName}`, 'info');
89
- console.log('========');
90
- console.log('\nNodes:', 'info');
91
- if (Object.entries(item.nodeTypes).length) {
92
- for (const [name, count] of Object.entries(item.nodeTypes)) {
93
- console.log(`- ${name}: ${count}`, 'info');
94
- }
95
- }
96
- if (Object.entries(item.scripts).length) {
97
- console.log('\nScripts:', 'info');
98
- for (const [name, desc] of Object.entries(item.scripts)) {
99
- console.log(`- ${name}: ${desc}`, 'info');
100
- }
101
- }
102
- if (Object.entries(item.emailTemplates).length) {
103
- console.log('\nEmail Templates:', 'info');
104
- for (const [id] of Object.entries(item.emailTemplates)) {
105
- console.log(`- ${id}`, 'info');
106
- }
82
+ const journeyData = await exportTree(options.journeyId);
83
+ describeTree(journeyData);
107
84
  }
108
85
  }
109
86
  }
@@ -1,9 +1,10 @@
1
1
  import { Command } from 'commander';
2
2
  import { Authenticate, Journey, state } from '@rockcarver/frodo-lib';
3
+ import yesno from 'yesno';
3
4
  import * as common from '../cmd_common.js';
4
5
 
5
6
  const { getTokens } = Authenticate;
6
- const { prune } = Journey;
7
+ const { findOrphanedNodes, removeOrphanedNodes } = Journey;
7
8
 
8
9
  const program = new Command('frodo journey prune');
9
10
 
@@ -32,7 +33,17 @@ program
32
33
  console.log(
33
34
  `Pruning orphaned configuration artifacts in realm "${state.default.session.getRealm()}"...`
34
35
  );
35
- prune();
36
+ const orphanedNodes = await findOrphanedNodes();
37
+ if (orphanedNodes.length > 0) {
38
+ const ok = await yesno({
39
+ question: 'Prune (permanently delete) orphaned nodes? (y|n):',
40
+ });
41
+ if (ok) {
42
+ await removeOrphanedNodes(orphanedNodes);
43
+ }
44
+ } else {
45
+ console.log('No orphaned nodes found.');
46
+ }
36
47
  }
37
48
  }
38
49
  // end command logic inside action handler