@contrail/cli 3.6.0-alpha-5 → 3.6.0-alpha-7

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/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.6.0-alpha-5 darwin-arm64 node-v22.19.0
20
+ @contrail/cli/3.6.0-alpha-7 darwin-arm64 node-v22.19.0
21
21
  $ contrail --help [COMMAND]
22
22
  USAGE
23
23
  $ contrail COMMAND
@@ -546,7 +546,7 @@ EXAMPLES
546
546
  ```
547
547
  USAGE
548
548
  $ contrail entities create PATH [-l error|warn|info|debug] [-e true|false] [-n <value>] [-d] [-i <value>] [-o
549
- <value>] [-p] [-r] [-s]
549
+ <value>] [-g] [-r] [-s]
550
550
 
551
551
  ARGUMENTS
552
552
  PATH Path of the entity type to create
@@ -555,15 +555,15 @@ FLAGS
555
555
  -d, --dryRun If true, does not create the entity but simulates the creation
556
556
  -e, --alwaysConfirmEnv=<option> [default: true] The Environment variables
557
557
  <options: true|false>
558
+ -g, --generateValues If true, generates random values for properties that are not specified. By default,
559
+ only specified properties are used.
558
560
  -i, --inputFile=<value> A file with a JSON array of objects where each object is one entity to create. Cannot
559
- be used with --count. Unless --precise is specified, any missing values will be
560
- populated with random values.
561
+ be used with --count. Unless --generate-values is specified, only the properties in
562
+ the file will be used.
561
563
  -l, --logLevel=<option> The Log Level
562
564
  <options: error|warn|info|debug>
563
565
  -n, --count=<value> Number of random entities to create
564
566
  -o, --outputFile=<value> File to save the output (optional)
565
- -p, --preciseProperties If true, does not generate random values for properties. All values must be
566
- specified.
567
567
  -r, --readableIds If true, uses readable IDs for the created entities
568
568
  -s, --skipHydrateRelationships If true, does not hydrate relationships for the created entities
569
569
 
@@ -571,23 +571,23 @@ DESCRIPTION
571
571
  (BETA) Create entities
572
572
 
573
573
  EXAMPLES
574
- $ contrail entities create color -n=10 # creates 10 random colors
574
+ $ contrail entities create color -g -n=10 # creates 10 random colors
575
575
 
576
- $ contrail entities create color # creates one item
576
+ $ contrail entities create color -- name="Electric Blue" green=1 red=2 blue=3 # creates one color with specified properties only
577
577
 
578
578
  $ contrail entities create custom-entities:franchise
579
579
 
580
580
  $ contrail entities create project-item -n=1 -- projectId=abc # creates 10 project items within project ABC
581
581
 
582
- $ contrail entities create color -r # creates a random color with a human readable ID
582
+ $ contrail entities create color -g -r # creates a random color with a human readable ID
583
583
 
584
- $ contrail entities create color -d # simulates the creation of a random color without actually creating it
584
+ $ contrail entities create color -d -- name=test # simulates the creation of a color without actually creating it
585
585
 
586
- $ contrail entities create custom-entity:franchise -s # creates a random color and the response does not contain hydrating relationships
586
+ $ contrail entities create custom-entity:franchise -s # creates an entity and the response does not contain hydrating relationships
587
587
 
588
- $ contrail entities create color -p -- name=Electric Blue green=1 red=2 blue=3 # creates a color with specified properties
588
+ $ contrail entities create color -g -- name=Electric Blue # creates a color with the name specified and other properties auto-generated
589
589
 
590
- $ contrail entities create color -o /tmp/colors.json # creates a random color and saves the output to /tmp/colors.json
590
+ $ contrail entities create color -o /tmp/colors.json -- name=Blue green=1 red=2 blue=3 # creates a color and saves the output to /tmp/colors.json
591
591
  ```
592
592
 
593
593
  ## `contrail entities delete ENTITYNAME`
@@ -11,7 +11,7 @@ export default class CreateEntity extends BaseCommand {
11
11
  dryRun: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
12
12
  inputFile: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
13
13
  outputFile: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
14
- preciseProperties: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
14
+ generateValues: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
15
15
  readableIds: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
16
16
  skipHydrateRelationships: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
17
17
  alwaysConfirmEnv: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
@@ -18,7 +18,7 @@ const file_helpers_1 = require("../../helpers/file-helpers");
18
18
  let IS_DRY_RUN = false;
19
19
  let SHOULD_USE_READABLE_IDS = false;
20
20
  let SHOULD_SKIP_HYDRATE_RELATIONSHIPS = false;
21
- let SHOULD_ONLY_USE_SPECIFIED_PROPERTIES = false;
21
+ let SHOULD_GENERATE_MISSING_VALUES = false;
22
22
  let NUM_ENTITIES_TO_CREATE = 1; // Default to creating one entity if not specified
23
23
  const getNumEntitiesToCreate = () => NUM_ENTITIES_TO_CREATE; // method to get the latest number in case this changes later
24
24
  const baseValidationMap = {
@@ -90,7 +90,8 @@ const FIND_VALID_VALUE_MAP = {
90
90
  if (entity.itemFamilyId)
91
91
  return; // skip if already specified
92
92
  if (entity.roles?.includes('option')) {
93
- entity.itemFamilyId = Array.from(validValues)[Math.floor(Math.random() * validValues.size)];
93
+ entity.itemFamilyId =
94
+ Array.from(validValues)[Math.floor(Math.random() * validValues.size)];
94
95
  // can reuse itemFamilyId for options
95
96
  }
96
97
  },
@@ -145,15 +146,15 @@ const FIND_VALID_VALUE_MAP = {
145
146
  class CreateEntity extends basecommand_1.BaseCommand {
146
147
  static description = '(BETA) Create entities';
147
148
  static examples = [
148
- 'contrail entities create color -n=10 # creates 10 random colors',
149
- 'contrail entities create color # creates one item',
149
+ 'contrail entities create color -g -n=10 # creates 10 random colors',
150
+ 'contrail entities create color -- name="Electric Blue" green=1 red=2 blue=3 # creates one color with specified properties only',
150
151
  'contrail entities create custom-entities:franchise',
151
152
  'contrail entities create project-item -n=1 -- projectId=abc # creates 10 project items within project ABC',
152
- 'contrail entities create color -r # creates a random color with a human readable ID',
153
- 'contrail entities create color -d # simulates the creation of a random color without actually creating it',
154
- 'contrail entities create custom-entity:franchise -s # creates a random color and the response does not contain hydrating relationships',
155
- 'contrail entities create color -p -- name=Electric Blue green=1 red=2 blue=3 # creates a color with specified properties',
156
- 'contrail entities create color -o /tmp/colors.json # creates a random color and saves the output to /tmp/colors.json',
153
+ 'contrail entities create color -g -r # creates a random color with a human readable ID',
154
+ 'contrail entities create color -d -- name=test # simulates the creation of a color without actually creating it',
155
+ 'contrail entities create custom-entity:franchise -s # creates an entity and the response does not contain hydrating relationships',
156
+ 'contrail entities create color -g -- name=Electric Blue # creates a color with the name specified and other properties auto-generated',
157
+ 'contrail entities create color -o /tmp/colors.json -- name=Blue green=1 red=2 blue=3 # creates a color and saves the output to /tmp/colors.json',
157
158
  ];
158
159
  static flags = {
159
160
  ...basecommand_1.BaseCommand.baseFlags,
@@ -170,7 +171,7 @@ class CreateEntity extends basecommand_1.BaseCommand {
170
171
  }),
171
172
  inputFile: core_1.Flags.string({
172
173
  char: 'i',
173
- description: 'A file with a JSON array of objects where each object is one entity to create. Cannot be used with --count. Unless --precise is specified, any missing values will be populated with random values.',
174
+ description: 'A file with a JSON array of objects where each object is one entity to create. Cannot be used with --count. Unless --generate-values is specified, only the properties in the file will be used.',
174
175
  required: false,
175
176
  multiple: false,
176
177
  }),
@@ -180,9 +181,9 @@ class CreateEntity extends basecommand_1.BaseCommand {
180
181
  required: false,
181
182
  multiple: false,
182
183
  }),
183
- preciseProperties: core_1.Flags.boolean({
184
- char: 'p',
185
- description: 'If true, does not generate random values for properties. All values must be specified.',
184
+ generateValues: core_1.Flags.boolean({
185
+ char: 'g',
186
+ description: 'If true, generates random values for properties that are not specified. By default, only specified properties are used.',
186
187
  required: false,
187
188
  default: false,
188
189
  }),
@@ -211,7 +212,7 @@ class CreateEntity extends basecommand_1.BaseCommand {
211
212
  this.log('🚨 This command is in BETA and may change or be removed at any time.');
212
213
  await (0, login_1.authUser)();
213
214
  const { flags, argv, args } = await this.parse(CreateEntity);
214
- const { count, dryRun: isDryRun, inputFile: inputFilename, outputFile: outputFilename, preciseProperties: shouldOnlyUseSpecifiedProperties, readableIds: shouldUseReadableIds, skipHydrateRelationships, } = flags;
215
+ const { count, dryRun: isDryRun, inputFile: inputFilename, outputFile: outputFilename, generateValues: shouldGenerateMissingValues, readableIds: shouldUseReadableIds, skipHydrateRelationships, } = flags;
215
216
  const { path: entityTypePath } = args;
216
217
  // Global flags is a little hacky, but it was easier
217
218
  // and it doesn't see *that* bad because they are only valid
@@ -219,7 +220,7 @@ class CreateEntity extends basecommand_1.BaseCommand {
219
220
  IS_DRY_RUN = isDryRun;
220
221
  SHOULD_USE_READABLE_IDS = shouldUseReadableIds;
221
222
  SHOULD_SKIP_HYDRATE_RELATIONSHIPS = skipHydrateRelationships;
222
- SHOULD_ONLY_USE_SPECIFIED_PROPERTIES = shouldOnlyUseSpecifiedProperties;
223
+ SHOULD_GENERATE_MISSING_VALUES = shouldGenerateMissingValues;
223
224
  const propertySpecificationArgs = argv
224
225
  .slice(1, argv.length)
225
226
  .filter(propertySpecifications_1.isValidPropertySpecification);
@@ -238,18 +239,24 @@ class CreateEntity extends basecommand_1.BaseCommand {
238
239
  ? (0, file_helpers_1.parseFileAsJsonArray)(inputFilename)
239
240
  : Array.from({ length: count || 1 }).fill({});
240
241
  NUM_ENTITIES_TO_CREATE = partialEntities.length;
242
+ const { root: entityName } = (0, types_2.parseTypePath)(entityTypePath);
241
243
  // Ensure we have the required properties for the entity type
242
- if (SLUGS_THAT_MUST_BE_SPECIFIED_BY_TYPE_PATH[entityTypePath]) {
243
- const requiredSlugs = SLUGS_THAT_MUST_BE_SPECIFIED_BY_TYPE_PATH[entityTypePath];
244
+ if (SLUGS_THAT_MUST_BE_SPECIFIED_BY_TYPE_PATH[entityName]) {
245
+ const requiredSlugs = SLUGS_THAT_MUST_BE_SPECIFIED_BY_TYPE_PATH[entityName];
244
246
  for (const slug of requiredSlugs) {
245
- if (!propertySpecBySlug.has(slug)) {
246
- this.error(`Property '${slug}' must be specified for entity type '${entityTypePath}'.`);
247
+ // Check if the property is specified in command-line args
248
+ const isInCommandLineArgs = propertySpecBySlug.has(slug);
249
+ // Check if all entities from input file have this property
250
+ const allEntitiesHaveProperty = inputFilename
251
+ ? partialEntities.every((entity) => entity[slug] !== undefined && entity[slug] !== null)
252
+ : false;
253
+ if (!isInCommandLineArgs && !allEntitiesHaveProperty) {
254
+ this.error(`Property '${slug}' must be specified for entity type '${entityName}'.`);
247
255
  }
248
256
  }
249
257
  }
250
258
  try {
251
259
  const entitiesToCreate = await buildEntitiesToCreate(entityTypePath, partialEntities, propertySpecBySlug);
252
- const { root: entityName } = (0, types_2.parseTypePath)(entityTypePath);
253
260
  const createdEntities = await createEntities(entityName, entitiesToCreate);
254
261
  if (outputFilename) {
255
262
  fs_1.default.writeFileSync(outputFilename, JSON.stringify(createdEntities, null, 2));
@@ -294,15 +301,26 @@ async function buildEntitiesToCreate(entityTypePath, entities, propertySpecifica
294
301
  }));
295
302
  const limit = (0, p_limit_1.default)(30);
296
303
  await Promise.all(populatedEntities.map(async () => limit(() => throwIfEntityIsInvalid)));
304
+ // Skip system value generation unless -g flag is set (generateValues mode)
305
+ if (!SHOULD_GENERATE_MISSING_VALUES) {
306
+ console.log('Using only specified properties. Use --generate-values to auto-generate missing values.');
307
+ return populatedEntities;
308
+ }
297
309
  // Add system values if needed
298
310
  const { root } = (0, types_2.parseTypePath)(type.typePath);
299
311
  const valueFinderApplierForEntity = FIND_VALID_VALUE_MAP[root] || [];
300
312
  for (const { slug, findValidValuesFn, applyValueToEntityFn } of valueFinderApplierForEntity) {
301
- // If the property is already specified, skip it unless it is a role for an option or family
313
+ // If the property is already specified in command-line args, skip it
302
314
  if (propertySpecificationBySlug?.has(slug)) {
303
315
  console.log(`Skipping property ${slug} because it is already specified.`);
304
316
  continue;
305
317
  }
318
+ // If all entities already have this property, skip finding values
319
+ const allEntitiesHaveProperty = populatedEntities.every((entity) => entity[slug] !== undefined && entity[slug] !== null);
320
+ if (allEntitiesHaveProperty) {
321
+ console.log(`Skipping property ${slug} because all entities already have this value.`);
322
+ continue;
323
+ }
306
324
  const values = await findValidValuesFn(populatedEntities, entities.length);
307
325
  if (values) {
308
326
  populatedEntities.forEach((e) => applyValueToEntityFn(e, values));
@@ -315,9 +333,9 @@ async function buildEntitiesToCreate(entityTypePath, entities, propertySpecifica
315
333
  }
316
334
  function createEntityWithPopulatedValues(type, typeReferencesCache, objectReferencesCache, propertySpecificationBySlug) {
317
335
  const roles = propertySpecificationBySlug?.get('roles');
318
- const entity = SHOULD_ONLY_USE_SPECIFIED_PROPERTIES
319
- ? {}
320
- : pickRandomPropertyValues(type, objectReferencesCache, typeReferencesCache, roles);
336
+ const entity = SHOULD_GENERATE_MISSING_VALUES
337
+ ? pickRandomPropertyValues(type, objectReferencesCache, typeReferencesCache, roles)
338
+ : {};
321
339
  // Handle property specifications
322
340
  for (const [propertySlug, specifiedValue] of propertySpecificationBySlug.entries()) {
323
341
  const correspondingProperty = type.typeProperties.find((prop) => getPropertySlug(prop) === propertySlug);
@@ -452,7 +470,10 @@ function generateRandomNumber(min, max) {
452
470
  return Math.floor(Math.random() * (max - min + 1)) + min;
453
471
  }
454
472
  function generateRandomReadableString() {
455
- return (0, unique_names_generator_1.uniqueNamesGenerator)({ dictionaries: [unique_names_generator_1.adjectives, unique_names_generator_1.animals, unique_names_generator_1.colors, unique_names_generator_1.animals, unique_names_generator_1.colors], length: 5 });
473
+ return (0, unique_names_generator_1.uniqueNamesGenerator)({
474
+ dictionaries: [unique_names_generator_1.adjectives, unique_names_generator_1.animals, unique_names_generator_1.colors, unique_names_generator_1.animals, unique_names_generator_1.colors],
475
+ length: 5,
476
+ });
456
477
  }
457
478
  function generateRandomDateString() {
458
479
  return new Date().toISOString();
@@ -148,7 +148,15 @@ async function getEntityByTypePath(typePath, propertySpec, options = {}) {
148
148
  if (entityName === 'custom-entity' && !id) {
149
149
  criteria.typePath = typePath;
150
150
  }
151
- return find(entityName, { id, skipHydrateRelationships, relations, propertySlugs, criteria, skip, take });
151
+ return find(entityName, {
152
+ id,
153
+ skipHydrateRelationships,
154
+ relations,
155
+ propertySlugs,
156
+ criteria,
157
+ skip,
158
+ take,
159
+ });
152
160
  }
153
161
  function convertPropertySpecIntoCriteria(propertySpec) {
154
162
  const criteria = {};
@@ -165,7 +173,7 @@ async function find(entityName, options = {}) {
165
173
  skipHydrateRelationships,
166
174
  relations,
167
175
  skip,
168
- take
176
+ take,
169
177
  };
170
178
  if (propertySlugs && propertySlugs.length > 0) {
171
179
  queryOptions.customParams = { propertySlugs: propertySlugs.join(',') };
@@ -37,7 +37,7 @@ class UpdateEntity extends basecommand_1.BaseCommand {
37
37
  char: 'F',
38
38
  description: 'Force update without validation. Internal use only',
39
39
  required: false,
40
- })
40
+ }),
41
41
  };
42
42
  static args = {
43
43
  entityName: core_1.Args.string({
@@ -55,7 +55,7 @@ class UpdateEntity extends basecommand_1.BaseCommand {
55
55
  await (0, login_1.authUser)();
56
56
  const { args, argv } = await this.parse(UpdateEntity);
57
57
  const { id: specifiedId, entityName } = args;
58
- const { dryRun: isDryRun, inputFile: inputFilename, skipHydrateRelationships, force } = this.flags;
58
+ const { dryRun: isDryRun, inputFile: inputFilename, skipHydrateRelationships, force, } = this.flags;
59
59
  const propertySpecArgs = argv.slice(1, argv.length).filter(propertySpecifications_1.isValidPropertySpecification);
60
60
  const propertySpec = (0, propertySpecifications_1.parsePropertySpecificationsIntoMap)(propertySpecArgs);
61
61
  if (inputFilename && specifiedId) {
@@ -71,7 +71,7 @@ async function uploadFile(incomingFileName) {
71
71
  async function loadFile(config) {
72
72
  const entities = new sdk_1.Entities();
73
73
  // start a load job referencing the newly created file
74
- logger_1.default.info(`Loading with config: ${config}`);
74
+ logger_1.default.info(`Loading with config: ${JSON.stringify(config, null, 2)}`);
75
75
  const loadJob = await entities.create({
76
76
  entityName: 'loader-process',
77
77
  object: {
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "3.6.0-alpha-5",
2
+ "version": "3.6.0-alpha-7",
3
3
  "commands": {
4
4
  "app:create": {
5
5
  "id": "app:create",
@@ -682,15 +682,15 @@
682
682
  "pluginType": "core",
683
683
  "aliases": [],
684
684
  "examples": [
685
- "contrail entities create color -n=10 # creates 10 random colors",
686
- "contrail entities create color # creates one item",
685
+ "contrail entities create color -g -n=10 # creates 10 random colors",
686
+ "contrail entities create color -- name=\"Electric Blue\" green=1 red=2 blue=3 # creates one color with specified properties only",
687
687
  "contrail entities create custom-entities:franchise",
688
688
  "contrail entities create project-item -n=1 -- projectId=abc # creates 10 project items within project ABC",
689
- "contrail entities create color -r # creates a random color with a human readable ID",
690
- "contrail entities create color -d # simulates the creation of a random color without actually creating it",
691
- "contrail entities create custom-entity:franchise -s # creates a random color and the response does not contain hydrating relationships",
692
- "contrail entities create color -p -- name=Electric Blue green=1 red=2 blue=3 # creates a color with specified properties",
693
- "contrail entities create color -o /tmp/colors.json # creates a random color and saves the output to /tmp/colors.json"
689
+ "contrail entities create color -g -r # creates a random color with a human readable ID",
690
+ "contrail entities create color -d -- name=test # simulates the creation of a color without actually creating it",
691
+ "contrail entities create custom-entity:franchise -s # creates an entity and the response does not contain hydrating relationships",
692
+ "contrail entities create color -g -- name=Electric Blue # creates a color with the name specified and other properties auto-generated",
693
+ "contrail entities create color -o /tmp/colors.json -- name=Blue green=1 red=2 blue=3 # creates a color and saves the output to /tmp/colors.json"
694
694
  ],
695
695
  "flags": {
696
696
  "logLevel": {
@@ -740,7 +740,7 @@
740
740
  "name": "inputFile",
741
741
  "type": "option",
742
742
  "char": "i",
743
- "description": "A file with a JSON array of objects where each object is one entity to create. Cannot be used with --count. Unless --precise is specified, any missing values will be populated with random values.",
743
+ "description": "A file with a JSON array of objects where each object is one entity to create. Cannot be used with --count. Unless --generate-values is specified, only the properties in the file will be used.",
744
744
  "required": false,
745
745
  "multiple": false
746
746
  },
@@ -752,11 +752,11 @@
752
752
  "required": false,
753
753
  "multiple": false
754
754
  },
755
- "preciseProperties": {
756
- "name": "preciseProperties",
755
+ "generateValues": {
756
+ "name": "generateValues",
757
757
  "type": "boolean",
758
- "char": "p",
759
- "description": "If true, does not generate random values for properties. All values must be specified.",
758
+ "char": "g",
759
+ "description": "If true, generates random values for properties that are not specified. By default, only specified properties are used.",
760
760
  "required": false,
761
761
  "allowNo": false
762
762
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrail/cli",
3
- "version": "3.6.0-alpha-5",
3
+ "version": "3.6.0-alpha-7",
4
4
  "description": "VibeIQ's Contrail Platform CLI.",
5
5
  "bin": {
6
6
  "contrail-cli": "./bin/run",