@contrail/cli 3.5.3-alpha.0e9434c → 3.5.3-alpha.297ad36

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 (39) hide show
  1. package/README.md +57 -12
  2. package/dist/api/org-config.d.ts +3 -0
  3. package/dist/api/org-config.js +28 -0
  4. package/dist/commands/groups/export.js +1 -13
  5. package/dist/commands/groups/import.js +2 -15
  6. package/dist/commands/instance/import.d.ts +14 -0
  7. package/dist/commands/instance/import.js +27 -5
  8. package/dist/commands/instance/import.spec.d.ts +1 -0
  9. package/dist/commands/instance/import.spec.js +57 -0
  10. package/dist/commands/org-config/export.d.ts +13 -0
  11. package/dist/commands/org-config/export.js +74 -0
  12. package/dist/commands/org-config/import.d.ts +12 -0
  13. package/dist/commands/org-config/import.js +63 -0
  14. package/dist/commands/types/getAll.js +2 -0
  15. package/dist/commands/types/loadAll.d.ts +13 -1
  16. package/dist/commands/types/loadAll.js +41 -4
  17. package/dist/commands/types/loadAll.spec.d.ts +1 -0
  18. package/dist/commands/types/loadAll.spec.js +77 -0
  19. package/dist/commands/types/mergeOptionSets.js +2 -9
  20. package/dist/commands/types/mergeTypeProperties.js +2 -6
  21. package/dist/commands/types/parseOptionSetsLocalFiles.js +3 -7
  22. package/dist/commands/types/uploadTypeOverrides.d.ts +10 -0
  23. package/dist/commands/types/uploadTypeOverrides.js +19 -8
  24. package/dist/commands/types/uploadTypeOverrides.spec.d.ts +1 -0
  25. package/dist/commands/types/uploadTypeOverrides.spec.js +60 -0
  26. package/dist/commands/users/export.js +1 -13
  27. package/dist/commands/users/import.js +2 -15
  28. package/dist/commands/workflow-templates/export.d.ts +1 -3
  29. package/dist/commands/workflow-templates/export.js +21 -110
  30. package/dist/helpers/error-helpers.d.ts +9 -0
  31. package/dist/helpers/error-helpers.js +35 -0
  32. package/dist/helpers/file-helpers.d.ts +2 -0
  33. package/dist/helpers/file-helpers.js +25 -1
  34. package/dist/helpers/projects/helpers.js +2 -6
  35. package/dist/helpers/types/type-parser.js +9 -15
  36. package/dist/helpers/workflow-templates/helper.d.ts +0 -1
  37. package/dist/helpers/workflow-templates/helper.js +6 -27
  38. package/oclif.manifest.json +122 -15
  39. package/package.json +4 -1
package/README.md CHANGED
@@ -17,7 +17,7 @@ $ npm install -g @contrail/cli
17
17
  $ contrail COMMAND
18
18
  running command...
19
19
  $ contrail (--version)
20
- @contrail/cli/3.5.3-alpha.0e9434c linux-x64 node-v24.16.0
20
+ @contrail/cli/3.5.3-alpha.297ad36 linux-x64 node-v24.20.0
21
21
  $ contrail --help [COMMAND]
22
22
  USAGE
23
23
  $ contrail COMMAND
@@ -61,6 +61,8 @@ To get instructions on how to set up autocomplete for your shell, run `contrail
61
61
  * [`contrail load custom-entity DATAFILE CONFIGFILE`](#contrail-load-custom-entity-datafile-configfile)
62
62
  * [`contrail load line-sheet DATAFILE CONFIGFILE`](#contrail-load-line-sheet-datafile-configfile)
63
63
  * [`contrail load upload-and-load INCOMINGFILE CONFIGFILENAME`](#contrail-load-upload-and-load-incomingfile-configfilename)
64
+ * [`contrail org-config export`](#contrail-org-config-export)
65
+ * [`contrail org-config import`](#contrail-org-config-import)
64
66
  * [`contrail projects export PROJECTNAME`](#contrail-projects-export-projectname)
65
67
  * [`contrail projects list`](#contrail-projects-list)
66
68
  * [`contrail projects load TEMPLATEFILELOCATION`](#contrail-projects-load-templatefilelocation)
@@ -777,6 +779,53 @@ EXAMPLES
777
779
  $ contrail load-processor upload-and-load <File Path> <Config Path>
778
780
  ```
779
781
 
782
+ ## `contrail org-config export`
783
+
784
+ Export the org config for your Org
785
+
786
+ ```
787
+ USAGE
788
+ $ contrail org-config export [-l error|warn|info|debug] [-e true|false] [-d <value>] [-f]
789
+
790
+ FLAGS
791
+ -d, --outDir=<value> [default: .] The directory to which to export the org config data. Defaults to the
792
+ current directory
793
+ -e, --alwaysConfirmEnv=<option> [default: true] The Environment variables
794
+ <options: true|false>
795
+ -f, --overwrite Replaces any existing export files in outDir
796
+ -l, --logLevel=<option> The Log Level
797
+ <options: error|warn|info|debug>
798
+
799
+ DESCRIPTION
800
+ Export the org config for your Org
801
+
802
+ EXAMPLES
803
+ $ contrail org-config export
804
+ ```
805
+
806
+ ## `contrail org-config import`
807
+
808
+ Upload an extracted org config
809
+
810
+ ```
811
+ USAGE
812
+ $ contrail org-config import [-l error|warn|info|debug] [-e true|false] [-d <value>]
813
+
814
+ FLAGS
815
+ -d, --dir=<value> [default: .] The directory from which to import the org config data. Defaults to the
816
+ current directory. The org config data will be loaded from $dir/org-config.yml
817
+ -e, --alwaysConfirmEnv=<option> [default: true] The Environment variables
818
+ <options: true|false>
819
+ -l, --logLevel=<option> The Log Level
820
+ <options: error|warn|info|debug>
821
+
822
+ DESCRIPTION
823
+ Upload an extracted org config
824
+
825
+ EXAMPLES
826
+ $ contrail org-config import
827
+ ```
828
+
780
829
  ## `contrail projects export PROJECTNAME`
781
830
 
782
831
  Export a project.
@@ -919,7 +968,7 @@ loads all the type data that has been exported by getAll
919
968
 
920
969
  ```
921
970
  USAGE
922
- $ contrail types loadAll [-l error|warn|info|debug] [-e true|false] [-d <value>]
971
+ $ contrail types loadAll [-l error|warn|info|debug] [-e true|false] [-d <value>] [--orgConfig]
923
972
 
924
973
  FLAGS
925
974
  -d, --dir=<value> [default: .] The directory from which to load the types data. Defaults to the current
@@ -928,6 +977,8 @@ FLAGS
928
977
  <options: true|false>
929
978
  -l, --logLevel=<option> The Log Level
930
979
  <options: error|warn|info|debug>
980
+ --[no-]orgConfig Also load org config data from this directory. If not specified, you will be
981
+ prompted.
931
982
 
932
983
  DESCRIPTION
933
984
  loads all the type data that has been exported by getAll
@@ -1611,31 +1662,25 @@ EXAMPLES
1611
1662
 
1612
1663
  ## `contrail workflow-templates export`
1613
1664
 
1614
- Export all workflows in the org. By default exports one file per app to the current directory.
1665
+ Export all workflows in the org.
1615
1666
 
1616
1667
  ```
1617
1668
  USAGE
1618
- $ contrail workflow-templates export [-l error|warn|info|debug] [-e true|false] [-f <value>] [-d <value>]
1619
- [--overwrite]
1669
+ $ contrail workflow-templates export [-l error|warn|info|debug] [-e true|false] [-f <value>] [--overwrite]
1620
1670
 
1621
1671
  FLAGS
1622
- -d, --dir=<value> [default: .] Directory to write per-app workflow files
1623
1672
  -e, --alwaysConfirmEnv=<option> [default: true] The Environment variables
1624
1673
  <options: true|false>
1625
- -f, --outFile=<value> Export all workflows to a single file at this path (overrides per-app export)
1674
+ -f, --outFile=<value> [default: workflows.yml] The location for the file to be saved
1626
1675
  -l, --logLevel=<option> The Log Level
1627
1676
  <options: error|warn|info|debug>
1628
1677
  --overwrite Replaces existing files if they exist
1629
1678
 
1630
1679
  DESCRIPTION
1631
- Export all workflows in the org. By default exports one file per app to the current directory.
1680
+ Export all workflows in the org.
1632
1681
 
1633
1682
  EXAMPLES
1634
1683
  $ contrail workflow-templates export
1635
-
1636
- $ contrail workflow-templates export --dir ./workflows
1637
-
1638
- $ contrail workflow-templates export --outFile workflows.yml
1639
1684
  ```
1640
1685
 
1641
1686
  ## `contrail workflow-templates list`
@@ -0,0 +1,3 @@
1
+ export declare function getOrgConfigs(options?: any): Promise<any[]>;
2
+ export declare function updateOrgConfig(id: string, changes: any): Promise<any>;
3
+ export declare function createOrgConfig(orgConfig: any): Promise<any>;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createOrgConfig = exports.updateOrgConfig = exports.getOrgConfigs = void 0;
4
+ const sdk_1 = require("@contrail/sdk");
5
+ // every org has exactly one org-config record (created at provisioning),
6
+ // so callers can safely use the first element of the returned list
7
+ async function getOrgConfigs(options) {
8
+ return new sdk_1.Entities().get({
9
+ entityName: 'org-config',
10
+ ...options,
11
+ });
12
+ }
13
+ exports.getOrgConfigs = getOrgConfigs;
14
+ async function updateOrgConfig(id, changes) {
15
+ return new sdk_1.Entities().update({
16
+ entityName: 'org-config',
17
+ id,
18
+ object: changes,
19
+ });
20
+ }
21
+ exports.updateOrgConfig = updateOrgConfig;
22
+ async function createOrgConfig(orgConfig) {
23
+ return new sdk_1.Entities().create({
24
+ entityName: 'org-config',
25
+ object: orgConfig,
26
+ });
27
+ }
28
+ exports.createOrgConfig = createOrgConfig;
@@ -2,11 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.exportGroups = exports.DEFAULT_FILE_LOCATION = void 0;
4
4
  const tslib_1 = require("tslib");
5
- const path = tslib_1.__importStar(require("path"));
6
5
  const chalk_1 = tslib_1.__importDefault(require("chalk"));
7
- const fs_1 = tslib_1.__importDefault(require("fs"));
8
6
  const login_1 = require("../../auth/login");
9
- const js_yaml_1 = tslib_1.__importDefault(require("js-yaml"));
10
7
  const core_1 = require("@oclif/core");
11
8
  const file_helpers_1 = require("../../helpers/file-helpers");
12
9
  const users_1 = require("../../api/users");
@@ -61,18 +58,9 @@ async function exportGroups(fileLocation, overwrite) {
61
58
  });
62
59
  }
63
60
  groups = groups.sort((one, two) => (one.name < two.name ? -1 : 1));
64
- await saveData(groups, fileLocation, overwrite);
61
+ await (0, file_helpers_1.saveData)(groups, fileLocation, overwrite);
65
62
  }
66
63
  exports.exportGroups = exportGroups;
67
- async function saveData(data, fileLocation, overwrite) {
68
- const yamlStr = js_yaml_1.default.dump(data);
69
- const CURRENT_DIR = process.cwd();
70
- const pathToWrite = path.join(CURRENT_DIR, fileLocation);
71
- if (fs_1.default.existsSync(pathToWrite)) {
72
- await (0, file_helpers_1.safeFileOverwrite)(pathToWrite, overwrite);
73
- }
74
- fs_1.default.writeFileSync(pathToWrite, yamlStr, 'utf8');
75
- }
76
64
  function getGroupPrincipals(group, allGroups, orgUsers) {
77
65
  if (!group?.groupPrincipals) {
78
66
  return [];
@@ -2,13 +2,11 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.uploadGroups = void 0;
4
4
  const tslib_1 = require("tslib");
5
- const path = tslib_1.__importStar(require("path"));
6
5
  const sdk_1 = require("@contrail/sdk");
7
6
  const chalk_1 = tslib_1.__importDefault(require("chalk"));
8
- const fs_1 = tslib_1.__importDefault(require("fs"));
9
7
  const login_1 = require("../../auth/login");
10
- const js_yaml_1 = tslib_1.__importDefault(require("js-yaml"));
11
8
  const core_1 = require("@oclif/core");
9
+ const file_helpers_1 = require("../../helpers/file-helpers");
12
10
  const basecommand_1 = require("../../basecommand");
13
11
  const logger_1 = tslib_1.__importDefault(require("../../logger"));
14
12
  class ImportGroups extends basecommand_1.BaseCommand {
@@ -39,23 +37,12 @@ class ImportGroups extends basecommand_1.BaseCommand {
39
37
  }
40
38
  }
41
39
  exports.default = ImportGroups;
42
- function getGroupsFile(fileLocation) {
43
- const CURRENT_DIR = process.cwd();
44
- try {
45
- const fullPath = path.join(CURRENT_DIR, fileLocation);
46
- const doc = js_yaml_1.default.load(fs_1.default.readFileSync(fullPath, 'utf8'));
47
- return doc;
48
- }
49
- catch (e) {
50
- throw new Error(`ERROR PARSING YAML: ${e}`);
51
- }
52
- }
53
40
  async function uploadGroups(fileLocation) {
54
41
  const existingGroups = await new sdk_1.Entities().get({
55
42
  entityName: 'group',
56
43
  relations: ['groupPrincipals'],
57
44
  });
58
- const groupsToImport = getGroupsFile(fileLocation);
45
+ const groupsToImport = (0, file_helpers_1.loadData)(fileLocation);
59
46
  const orgUsers = await new sdk_1.Entities().get({
60
47
  entityName: 'user-org',
61
48
  });
@@ -9,3 +9,17 @@ export default class ImportInstance extends BaseCommand {
9
9
  };
10
10
  run(): Promise<void>;
11
11
  }
12
+ /**
13
+ * Imports an instance export in dependency order:
14
+ * 1. option sets, types, option set hierarchies, rule sets
15
+ * 2. users and groups (policy principals)
16
+ * 3. type property policies and type policies
17
+ * 4. type overrides — after policies, because they reference policies, rule sets and option
18
+ * set hierarchies by slug and the API rejects the whole upload if any of them is missing
19
+ * 5. org config
20
+ *
21
+ * Fails (rejects) if the type overrides could not be applied, so the import does not
22
+ * report success while the org is missing customizations carried by overrides
23
+ * (labels/formulas/editability of core properties, subtype-level property changes).
24
+ */
25
+ export declare function importInstance(dir: string): Promise<void>;
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.importInstance = void 0;
3
4
  const tslib_1 = require("tslib");
4
5
  const path = tslib_1.__importStar(require("path"));
5
6
  const core_1 = require("@oclif/core");
@@ -8,6 +9,8 @@ const import_1 = require("../users/import");
8
9
  const import_2 = require("../groups/import");
9
10
  const uploadTypePropertyPolicies_1 = require("../types/uploadTypePropertyPolicies");
10
11
  const uploadTypePolicies_1 = require("../types/uploadTypePolicies");
12
+ const uploadTypeOverrides_1 = require("../types/uploadTypeOverrides");
13
+ const import_3 = require("../org-config/import");
11
14
  const basecommand_1 = require("../../basecommand");
12
15
  class ImportInstance extends basecommand_1.BaseCommand {
13
16
  static description = 'Import the data to an instance, including types and users';
@@ -25,11 +28,30 @@ class ImportInstance extends basecommand_1.BaseCommand {
25
28
  }),
26
29
  };
27
30
  async run() {
28
- await (0, loadAll_1.loadAll)(this.flags.dir, true);
29
- await (0, import_1.uploadUsers)(path.join(this.flags.dir, 'users.yml'));
30
- await (0, import_2.uploadGroups)(path.join(this.flags.dir, 'groups.yml'));
31
- await (0, uploadTypePropertyPolicies_1.uploadTypePropertyPolicies)(this.flags.dir);
32
- await (0, uploadTypePolicies_1.uploadTypePolicies)(this.flags.dir);
31
+ await importInstance(this.flags.dir);
33
32
  }
34
33
  }
35
34
  exports.default = ImportInstance;
35
+ /**
36
+ * Imports an instance export in dependency order:
37
+ * 1. option sets, types, option set hierarchies, rule sets
38
+ * 2. users and groups (policy principals)
39
+ * 3. type property policies and type policies
40
+ * 4. type overrides — after policies, because they reference policies, rule sets and option
41
+ * set hierarchies by slug and the API rejects the whole upload if any of them is missing
42
+ * 5. org config
43
+ *
44
+ * Fails (rejects) if the type overrides could not be applied, so the import does not
45
+ * report success while the org is missing customizations carried by overrides
46
+ * (labels/formulas/editability of core properties, subtype-level property changes).
47
+ */
48
+ async function importInstance(dir) {
49
+ await (0, loadAll_1.loadAll)(dir, true, false);
50
+ await (0, import_1.uploadUsers)(path.join(dir, 'users.yml'));
51
+ await (0, import_2.uploadGroups)(path.join(dir, 'groups.yml'));
52
+ await (0, uploadTypePropertyPolicies_1.uploadTypePropertyPolicies)(dir);
53
+ await (0, uploadTypePolicies_1.uploadTypePolicies)(dir);
54
+ await (0, uploadTypeOverrides_1.uploadTypeOverrides)(dir);
55
+ await (0, import_3.uploadOrgConfig)(dir);
56
+ }
57
+ exports.importInstance = importInstance;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const import_1 = require("./import");
4
+ const loadAll_1 = require("../types/loadAll");
5
+ const import_2 = require("../users/import");
6
+ const import_3 = require("../groups/import");
7
+ const uploadTypePropertyPolicies_1 = require("../types/uploadTypePropertyPolicies");
8
+ const uploadTypePolicies_1 = require("../types/uploadTypePolicies");
9
+ const uploadTypeOverrides_1 = require("../types/uploadTypeOverrides");
10
+ const import_4 = require("../org-config/import");
11
+ jest.mock('../types/loadAll');
12
+ jest.mock('../users/import');
13
+ jest.mock('../groups/import');
14
+ jest.mock('../types/uploadTypePropertyPolicies');
15
+ jest.mock('../types/uploadTypePolicies');
16
+ jest.mock('../types/uploadTypeOverrides');
17
+ jest.mock('../org-config/import');
18
+ const mocked = (fn) => fn;
19
+ const STEPS = [
20
+ loadAll_1.loadAll,
21
+ import_2.uploadUsers,
22
+ import_3.uploadGroups,
23
+ uploadTypePropertyPolicies_1.uploadTypePropertyPolicies,
24
+ uploadTypePolicies_1.uploadTypePolicies,
25
+ uploadTypeOverrides_1.uploadTypeOverrides,
26
+ import_4.uploadOrgConfig,
27
+ ];
28
+ describe('importInstance', () => {
29
+ beforeEach(() => {
30
+ jest.clearAllMocks();
31
+ for (const fn of STEPS) {
32
+ mocked(fn).mockResolvedValue(undefined);
33
+ }
34
+ });
35
+ it('skips policies/overrides/org-config in loadAll and uploads them after users and groups', async () => {
36
+ await (0, import_1.importInstance)('export-dir');
37
+ expect(mocked(loadAll_1.loadAll)).toHaveBeenCalledWith('export-dir', true, false);
38
+ expect(mocked(uploadTypeOverrides_1.uploadTypeOverrides)).toHaveBeenCalledWith('export-dir');
39
+ expect(mocked(import_4.uploadOrgConfig)).toHaveBeenCalledWith('export-dir');
40
+ const order = STEPS.map((fn) => mocked(fn).mock.invocationCallOrder[0]);
41
+ // strictly increasing => called in exactly this order
42
+ for (let i = 1; i < order.length; i++) {
43
+ expect(order[i]).toBeGreaterThan(order[i - 1]);
44
+ }
45
+ });
46
+ it('uploads type overrides after type policies (CR-2095)', async () => {
47
+ await (0, import_1.importInstance)('export-dir');
48
+ const policiesOrder = mocked(uploadTypePolicies_1.uploadTypePolicies).mock.invocationCallOrder[0];
49
+ const overridesOrder = mocked(uploadTypeOverrides_1.uploadTypeOverrides).mock.invocationCallOrder[0];
50
+ expect(overridesOrder).toBeGreaterThan(policiesOrder);
51
+ });
52
+ it('rejects when the type override upload fails instead of reporting success', async () => {
53
+ mocked(uploadTypeOverrides_1.uploadTypeOverrides).mockRejectedValue(new Error('policy with identifier X not found'));
54
+ await expect((0, import_1.importInstance)('export-dir')).rejects.toThrow('policy with identifier X not found');
55
+ expect(mocked(import_4.uploadOrgConfig)).not.toHaveBeenCalled();
56
+ });
57
+ });
@@ -0,0 +1,13 @@
1
+ import { BaseCommand } from '../../basecommand';
2
+ export default class ExportOrgConfig extends BaseCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ outDir: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
7
+ overwrite: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
8
+ alwaysConfirmEnv: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
9
+ logLevel: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
10
+ };
11
+ run(): Promise<void>;
12
+ }
13
+ export declare function exportOrgConfig(outDir: string, overwrite: boolean): Promise<void>;
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.exportOrgConfig = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const path = tslib_1.__importStar(require("path"));
6
+ const chalk_1 = tslib_1.__importDefault(require("chalk"));
7
+ const fs_1 = tslib_1.__importDefault(require("fs"));
8
+ const login_1 = require("../../auth/login");
9
+ const core_1 = require("@oclif/core");
10
+ const file_helpers_1 = require("../../helpers/file-helpers");
11
+ const org_config_1 = require("../../api/org-config");
12
+ const basecommand_1 = require("../../basecommand");
13
+ const logger_1 = tslib_1.__importDefault(require("../../logger"));
14
+ const ORG_SPECIFIC_FIELDS = [
15
+ 'id',
16
+ 'orgId',
17
+ 'createdOn',
18
+ 'updatedOn',
19
+ 'createdById',
20
+ 'updatedById',
21
+ 'createdBy',
22
+ 'updatedBy',
23
+ ];
24
+ class ExportOrgConfig extends basecommand_1.BaseCommand {
25
+ static description = 'Export the org config for your Org';
26
+ static examples = [
27
+ `$ contrail org-config export
28
+ `,
29
+ ];
30
+ static flags = {
31
+ ...basecommand_1.BaseCommand.baseFlags,
32
+ outDir: core_1.Flags.string({
33
+ char: 'd',
34
+ description: 'The directory to which to export the org config data. Defaults to the current directory',
35
+ required: false,
36
+ default: '.',
37
+ }),
38
+ overwrite: core_1.Flags.boolean({
39
+ char: 'f',
40
+ description: 'Replaces any existing export files in outDir',
41
+ required: false,
42
+ default: false,
43
+ }),
44
+ };
45
+ async run() {
46
+ try {
47
+ await (0, login_1.authUser)();
48
+ this.log(`${chalk_1.default.blue.bold('START')} Getting Org Config.`);
49
+ this.log(`${chalk_1.default.yellow.bold('ORG CONFIG')} Exporting`);
50
+ await exportOrgConfig(this.flags.outDir, this.flags.overwrite);
51
+ this.log(`${chalk_1.default.yellow.bold('ORG CONFIG')} Exported`);
52
+ }
53
+ catch (e) {
54
+ this.log(`${chalk_1.default.red.bold('FAIL')} Org Config Export Failed. ${e}`);
55
+ return;
56
+ }
57
+ this.log(`${chalk_1.default.green.bold('COMPLETE')} Org Config Export Complete.`);
58
+ }
59
+ }
60
+ exports.default = ExportOrgConfig;
61
+ async function exportOrgConfig(outDir, overwrite) {
62
+ const orgConfigs = await (0, org_config_1.getOrgConfigs)();
63
+ if (!orgConfigs?.length) {
64
+ logger_1.default.info(`${chalk_1.default.yellow.bold('ORG CONFIG')} No org config found. Skipping.`);
65
+ return;
66
+ }
67
+ const orgConfig = { ...orgConfigs[0] };
68
+ for (const field of ORG_SPECIFIC_FIELDS) {
69
+ delete orgConfig[field];
70
+ }
71
+ fs_1.default.mkdirSync(path.resolve(outDir), { recursive: true });
72
+ await (0, file_helpers_1.saveData)(orgConfig, path.join(outDir, 'org-config.yml'), overwrite);
73
+ }
74
+ exports.exportOrgConfig = exportOrgConfig;
@@ -0,0 +1,12 @@
1
+ import { BaseCommand } from '../../basecommand';
2
+ export default class ImportOrgConfig extends BaseCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ dir: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
7
+ alwaysConfirmEnv: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
8
+ logLevel: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
9
+ };
10
+ run(): Promise<void>;
11
+ }
12
+ export declare function uploadOrgConfig(dir: string): Promise<void>;
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.uploadOrgConfig = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const path = tslib_1.__importStar(require("path"));
6
+ const chalk_1 = tslib_1.__importDefault(require("chalk"));
7
+ const fs_1 = tslib_1.__importDefault(require("fs"));
8
+ const login_1 = require("../../auth/login");
9
+ const core_1 = require("@oclif/core");
10
+ const file_helpers_1 = require("../../helpers/file-helpers");
11
+ const org_config_1 = require("../../api/org-config");
12
+ const basecommand_1 = require("../../basecommand");
13
+ const logger_1 = tslib_1.__importDefault(require("../../logger"));
14
+ class ImportOrgConfig extends basecommand_1.BaseCommand {
15
+ static description = 'Upload an extracted org config';
16
+ static examples = [
17
+ `$ contrail org-config import
18
+ `,
19
+ ];
20
+ static flags = {
21
+ ...basecommand_1.BaseCommand.baseFlags,
22
+ dir: core_1.Flags.string({
23
+ char: 'd',
24
+ description: 'The directory from which to import the org config data. Defaults to the current directory. The org config data will be loaded from $dir/org-config.yml',
25
+ required: false,
26
+ default: '.',
27
+ }),
28
+ };
29
+ async run() {
30
+ try {
31
+ await (0, login_1.authUser)();
32
+ this.log(`${chalk_1.default.blue.bold('START')} Uploading Org Config.`);
33
+ this.log(`${chalk_1.default.yellow.bold('ORG CONFIG')} Uploading`);
34
+ await uploadOrgConfig(this.flags.dir);
35
+ this.log(`${chalk_1.default.yellow.bold('ORG CONFIG')} Uploaded`);
36
+ }
37
+ catch (e) {
38
+ this.log(`${chalk_1.default.red.bold('FAIL')} Org Config Upload Failed. ${e}`);
39
+ return;
40
+ }
41
+ this.log(`${chalk_1.default.green.bold('COMPLETE')} Org Config Upload Complete.`);
42
+ }
43
+ }
44
+ exports.default = ImportOrgConfig;
45
+ async function uploadOrgConfig(dir) {
46
+ const filePath = path.join(dir, 'org-config.yml');
47
+ if (!fs_1.default.existsSync(filePath)) {
48
+ logger_1.default.info(`${chalk_1.default.yellow.bold('ORG CONFIG')} No org config found in ${dir}. Skipping.`);
49
+ return;
50
+ }
51
+ const orgConfig = (0, file_helpers_1.loadData)(filePath);
52
+ if (!orgConfig || typeof orgConfig !== 'object' || Array.isArray(orgConfig)) {
53
+ throw new Error(`${filePath} must contain a single YAML object`);
54
+ }
55
+ const existingOrgConfigs = await (0, org_config_1.getOrgConfigs)();
56
+ if (existingOrgConfigs?.length) {
57
+ await (0, org_config_1.updateOrgConfig)(existingOrgConfigs[0].id, orgConfig);
58
+ }
59
+ else {
60
+ await (0, org_config_1.createOrgConfig)(orgConfig);
61
+ }
62
+ }
63
+ exports.uploadOrgConfig = uploadOrgConfig;
@@ -11,6 +11,7 @@ const type_extractor_1 = require("../../helpers/types/type-extractor");
11
11
  const types_1 = require("../../api/types");
12
12
  const types_2 = require("@contrail/org-config-migration/lib/types");
13
13
  const file_helpers_1 = require("../../helpers/file-helpers");
14
+ const export_1 = require("../org-config/export");
14
15
  const basecommand_1 = require("../../basecommand");
15
16
  const logger_1 = tslib_1.__importDefault(require("../../logger"));
16
17
  const js_yaml_1 = tslib_1.__importDefault(require("js-yaml"));
@@ -64,6 +65,7 @@ async function getAll(outDir, overwrite) {
64
65
  };
65
66
  const reducedData = await (0, types_2.getAllReducedTypes)(data);
66
67
  await saveData(reducedData, outDir, overwrite);
68
+ await (0, export_1.exportOrgConfig)(outDir, overwrite);
67
69
  logger_1.default.info(`${chalk_1.default.yellow.bold('TYPES')} Retrieved`);
68
70
  }
69
71
  catch (e) {
@@ -4,9 +4,21 @@ export default class LoadAllTypes extends BaseCommand {
4
4
  static examples: string[];
5
5
  static flags: {
6
6
  dir: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
7
+ orgConfig: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
7
8
  alwaysConfirmEnv: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
8
9
  logLevel: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
9
10
  };
10
11
  run(): Promise<void>;
11
12
  }
12
- export declare function loadAll(dir: string, skipPolicies?: boolean): Promise<void>;
13
+ /**
14
+ * Loads everything exported by `types getAll`.
15
+ *
16
+ * @param dir directory containing the export
17
+ * @param skipPolicies when true, type property policies, type policies AND type overrides are
18
+ * not uploaded. Policies need users/groups to exist first, and type overrides can reference
19
+ * policies (as well as rule sets and option set hierarchies), so the API rejects the whole
20
+ * override upload if a referenced policy is missing. Callers that pass `true` (e.g.
21
+ * `instance import`) must upload policies and then overrides themselves, in that order.
22
+ * @param loadOrgConfig whether to also load org-config.yml; prompts when undefined
23
+ */
24
+ export declare function loadAll(dir: string, skipPolicies?: boolean, loadOrgConfig?: boolean): Promise<void>;
@@ -4,6 +4,7 @@ exports.loadAll = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const core_1 = require("@oclif/core");
6
6
  const chalk_1 = tslib_1.__importDefault(require("chalk"));
7
+ const inquirer_1 = tslib_1.__importDefault(require("inquirer"));
7
8
  const login_1 = require("../../auth/login");
8
9
  const uploadOptionSets_1 = require("./uploadOptionSets");
9
10
  const uploadOptionSetHierarchies_1 = require("./uploadOptionSetHierarchies");
@@ -12,8 +13,10 @@ const uploadTypePropertyPolicies_1 = require("./uploadTypePropertyPolicies");
12
13
  const type_uploader_1 = require("../../helpers/types/type-uploader");
13
14
  const uploadTypeOverrides_1 = require("./uploadTypeOverrides");
14
15
  const uploadTypePolicies_1 = require("./uploadTypePolicies");
16
+ const import_1 = require("../org-config/import");
15
17
  const basecommand_1 = require("../../basecommand");
16
18
  const logger_1 = tslib_1.__importDefault(require("../../logger"));
19
+ const error_helpers_1 = require("../../helpers/error-helpers");
17
20
  class LoadAllTypes extends basecommand_1.BaseCommand {
18
21
  static description = 'loads all the type data that has been exported by getAll';
19
22
  static examples = [
@@ -28,13 +31,30 @@ class LoadAllTypes extends basecommand_1.BaseCommand {
28
31
  required: false,
29
32
  default: '.',
30
33
  }),
34
+ orgConfig: core_1.Flags.boolean({
35
+ description: 'Also load org config data from this directory. If not specified, you will be prompted.',
36
+ required: false,
37
+ default: undefined,
38
+ allowNo: true,
39
+ }),
31
40
  };
32
41
  async run() {
33
- await loadAll(this.flags.dir);
42
+ await loadAll(this.flags.dir, false, this.flags.orgConfig);
34
43
  }
35
44
  }
36
45
  exports.default = LoadAllTypes;
37
- async function loadAll(dir, skipPolicies = false) {
46
+ /**
47
+ * Loads everything exported by `types getAll`.
48
+ *
49
+ * @param dir directory containing the export
50
+ * @param skipPolicies when true, type property policies, type policies AND type overrides are
51
+ * not uploaded. Policies need users/groups to exist first, and type overrides can reference
52
+ * policies (as well as rule sets and option set hierarchies), so the API rejects the whole
53
+ * override upload if a referenced policy is missing. Callers that pass `true` (e.g.
54
+ * `instance import`) must upload policies and then overrides themselves, in that order.
55
+ * @param loadOrgConfig whether to also load org-config.yml; prompts when undefined
56
+ */
57
+ async function loadAll(dir, skipPolicies = false, loadOrgConfig) {
38
58
  try {
39
59
  await (0, login_1.authUser)();
40
60
  await (0, uploadOptionSets_1.uploadOptionSets)(dir);
@@ -44,11 +64,28 @@ async function loadAll(dir, skipPolicies = false) {
44
64
  if (!skipPolicies) {
45
65
  await (0, uploadTypePropertyPolicies_1.uploadTypePropertyPolicies)(dir);
46
66
  await (0, uploadTypePolicies_1.uploadTypePolicies)(dir);
67
+ // must run after policies, rule sets and option set hierarchies: overrides reference them by slug
68
+ await (0, uploadTypeOverrides_1.uploadTypeOverrides)(dir);
69
+ }
70
+ let shouldLoadOrgConfig = loadOrgConfig;
71
+ if (shouldLoadOrgConfig === undefined) {
72
+ const answers = await inquirer_1.default.prompt([
73
+ {
74
+ type: 'confirm',
75
+ name: 'loadOrgConfig',
76
+ message: 'Also load org config details from this directory?',
77
+ default: false,
78
+ },
79
+ ]);
80
+ shouldLoadOrgConfig = answers.loadOrgConfig;
81
+ }
82
+ if (shouldLoadOrgConfig) {
83
+ await (0, import_1.uploadOrgConfig)(dir);
47
84
  }
48
- await (0, uploadTypeOverrides_1.uploadTypeOverrides)(dir);
49
85
  }
50
86
  catch (e) {
51
- logger_1.default.info(`${chalk_1.default.red.bold('FAIL')} Types Upload Failed. ${e}`);
87
+ logger_1.default.error(`${chalk_1.default.red.bold('FAIL')} Types Upload Failed. ${(0, error_helpers_1.describeError)(e)}`);
88
+ process.exitCode = 1;
52
89
  return;
53
90
  }
54
91
  logger_1.default.info(`${chalk_1.default.green.bold('COMPLETE')} Types Upload Complete.`);
@@ -0,0 +1 @@
1
+ export {};