@contrail/cli 3.6.0-alpha-8-alpha.19e980d → 3.6.0-alpha-8-alpha.828359d

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-8-alpha.19e980d linux-x64 node-v24.21.0
20
+ @contrail/cli/3.6.0-alpha-8-alpha.828359d linux-x64 node-v24.21.0
21
21
  $ contrail --help [COMMAND]
22
22
  USAGE
23
23
  $ contrail COMMAND
@@ -686,7 +686,7 @@ Update an entity
686
686
 
687
687
  ```
688
688
  USAGE
689
- $ contrail entities update ENTITYNAME [IDS] [-l error|warn|info|debug] [-e true|false] [-S] [-d] [-i <value>] [-F]
689
+ $ contrail entities update ENTITYNAME [IDS] [-l error|warn|info|debug] [-e true|false] [-S] [-d] [-i <value>]
690
690
  [--suffix <value>] [--apiVersion 1|2]
691
691
 
692
692
  ARGUMENTS
@@ -694,12 +694,11 @@ ARGUMENTS
694
694
  IDS One or more entity ids to update
695
695
 
696
696
  FLAGS
697
- -F, --force Force update without validation. Internal use only
698
697
  -S, --skipHydrateRelationships Skip hydrating relationships when updating the entity
699
- -d, --dryRun If true, does not create the entity but simulates the creation
698
+ -d, --dryRun If true, does not update the entities but simulates the update
700
699
  -e, --alwaysConfirmEnv=<option> [default: true] The Environment variables
701
700
  <options: true|false>
702
- -i, --inputFile=<value> File containing properties to update the entity (optional)
701
+ -i, --inputFile=<value> A file with a JSON array of {id, ...} objects; each object is one entity to update.
703
702
  -l, --logLevel=<option> The Log Level
704
703
  <options: error|warn|info|debug>
705
704
  --apiVersion=<option> Api-Version header to send; selects the V1 or V2 variant of the endpoint
@@ -91,8 +91,8 @@ class DeleteEntity extends basecommand_1.BaseCommand {
91
91
  console.error('deleted entities:');
92
92
  }
93
93
  this.log(JSON.stringify(response, null, 2));
94
- if (response.idsErrored.length > 0) {
95
- console.error(`${response.idsErrored.length} of ${ids.length} deletes failed.`);
94
+ if (response.failed.length > 0) {
95
+ console.error(`${response.failed.length} of ${ids.length} deletes failed.`);
96
96
  process.exitCode = 1;
97
97
  }
98
98
  }
@@ -103,32 +103,26 @@ class DeleteEntity extends basecommand_1.BaseCommand {
103
103
  }
104
104
  exports.default = DeleteEntity;
105
105
  async function deleteEntityByIds(entityName, ids, routing = {}) {
106
- const idsDeleted = new Set();
107
- const idsNotFound = new Set();
108
- const idsErrored = new Set();
106
+ const deletedIds = [];
107
+ const notFoundIds = [];
108
+ const failed = [];
109
109
  const limit = (0, p_limit_1.default)(10);
110
110
  const deletePromises = ids.map((id) => limit(() => deleteEntityById(entityName, id, routing).then((entity) => {
111
111
  if (!entity) {
112
- idsNotFound.add(id);
113
- return null;
112
+ notFoundIds.push(id);
113
+ return;
114
114
  }
115
- idsDeleted.add(id);
116
- return entity;
115
+ deletedIds.push(id);
117
116
  }, (error) => {
118
117
  if (error.message.includes('not found')) {
119
- idsNotFound.add(id);
118
+ notFoundIds.push(id);
120
119
  }
121
120
  else {
122
- idsErrored.add(id);
121
+ failed.push({ id, error: (0, common_1.sdkErrorMessage)(error) });
123
122
  }
124
- return null;
125
123
  })));
126
124
  await Promise.all(deletePromises);
127
- return {
128
- idsDeleted: Array.from(idsDeleted),
129
- idsNotFound: Array.from(idsNotFound),
130
- idsErrored: Array.from(idsErrored),
131
- };
125
+ return { deletedIds, notFoundIds, failed };
132
126
  }
133
127
  async function deleteEntityById(entityName, id, routing = {}) {
134
128
  const client = new sdk_1.Entities();
@@ -157,6 +157,9 @@ class GetEntity extends basecommand_1.BaseCommand {
157
157
  apiVersion: apiVersion,
158
158
  take,
159
159
  });
160
+ if (response === null) {
161
+ this.error(`Entity not found: ${propertySpecBySlug.get('id')}`, { exit: 1 });
162
+ }
160
163
  if (outputFile) {
161
164
  fs_1.default.writeFileSync(outputFile, JSON.stringify(response, null, 2));
162
165
  console.error(`Output saved to ${outputFile}`);
@@ -167,6 +170,9 @@ class GetEntity extends basecommand_1.BaseCommand {
167
170
  }
168
171
  }
169
172
  catch (e) {
173
+ if (e.message?.startsWith('Entity not found:')) {
174
+ throw e;
175
+ }
170
176
  this.error(`Error fetching entity: ${e.message}`);
171
177
  }
172
178
  }
@@ -182,6 +188,8 @@ async function getEntityByTypePath(typePath, propertySpec, options = {}) {
182
188
  }
183
189
  return find(entityName, {
184
190
  id,
191
+ // a missing id returns null (no retries); the command turns it into a clean not-found error
192
+ ignore404: id !== undefined,
185
193
  skipHydrateRelationships,
186
194
  relations,
187
195
  propertySlugs,
@@ -201,9 +209,10 @@ function convertPropertySpecIntoCriteria(propertySpec) {
201
209
  }
202
210
  async function find(entityName, options = {}) {
203
211
  const client = new sdk_1.Entities();
204
- const { criteria, id, propertySlugs, skipHydrateRelationships, relations, skip, suffix, apiVersion, take, } = options;
212
+ const { criteria, id, ignore404, propertySlugs, skipHydrateRelationships, relations, skip, suffix, apiVersion, take, } = options;
205
213
  const queryOptions = {
206
214
  entityName,
215
+ ignore404,
207
216
  skipHydrateRelationships,
208
217
  relations,
209
218
  skip,
@@ -6,7 +6,6 @@ export default class UpdateEntity extends BaseCommand {
6
6
  skipHydrateRelationships: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
7
7
  dryRun: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
8
8
  inputFile: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
9
- force: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
10
9
  suffix: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
11
10
  apiVersion: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
12
11
  alwaysConfirmEnv: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces/parser").CustomOptions>;
@@ -27,18 +27,13 @@ class UpdateEntity extends basecommand_1.BaseCommand {
27
27
  }),
28
28
  dryRun: core_1.Flags.boolean({
29
29
  char: 'd',
30
- description: 'If true, does not create the entity but simulates the creation',
30
+ description: 'If true, does not update the entities but simulates the update',
31
31
  required: false,
32
32
  default: false,
33
33
  }),
34
34
  inputFile: core_1.Flags.string({
35
35
  char: 'i',
36
- description: 'File containing properties to update the entity (optional)',
37
- required: false,
38
- }),
39
- force: core_1.Flags.boolean({
40
- char: 'F',
41
- description: 'Force update without validation. Internal use only',
36
+ description: 'A file with a JSON array of {id, ...} objects; each object is one entity to update.',
42
37
  required: false,
43
38
  }),
44
39
  suffix: core_1.Flags.string({
@@ -67,7 +62,7 @@ class UpdateEntity extends basecommand_1.BaseCommand {
67
62
  await (0, login_1.authUser)();
68
63
  const { args, argv } = await this.parse(UpdateEntity);
69
64
  const { entityName } = args;
70
- const { dryRun: isDryRun, inputFile: inputFilename, skipHydrateRelationships, suffix, apiVersion, force, } = this.flags;
65
+ const { dryRun: isDryRun, inputFile: inputFilename, skipHydrateRelationships, suffix, apiVersion, } = this.flags;
71
66
  const { ids: positionalIds, specs } = (0, propertySpecifications_1.partitionIdsAndSpecs)(argv.slice(1));
72
67
  const propertySpec = (0, propertySpecifications_1.parsePropertySpecificationsIntoMap)(specs);
73
68
  if (propertySpec.has('id') || propertySpec.has('ids')) {
@@ -101,7 +96,6 @@ class UpdateEntity extends basecommand_1.BaseCommand {
101
96
  skipHydrateRelationships,
102
97
  suffix,
103
98
  apiVersion: apiVersion,
104
- force,
105
99
  });
106
100
  }
107
101
  try {
@@ -142,7 +136,7 @@ function summarizeSettledUpdates(inputs, settled, skipped) {
142
136
  exports.summarizeSettledUpdates = summarizeSettledUpdates;
143
137
  async function updateEntityById(entityName, id, changes, options = {}) {
144
138
  const client = new sdk_1.Entities();
145
- const { skipHydrateRelationships, suffix, apiVersion, force } = options;
139
+ const { skipHydrateRelationships, suffix, apiVersion } = options;
146
140
  return client.update({
147
141
  entityName,
148
142
  id,
@@ -68,7 +68,8 @@ function parsePropertySpecificationsIntoMap(propertySpecifications) {
68
68
  // ids is the one comma-split exception: it is a list of ids by definition
69
69
  // and ids never contain commas.
70
70
  const idsArray = value.split(',').map((id) => id.trim());
71
- propertySpecBySlug.set(slug, idsArray);
71
+ const existingIds = propertySpecBySlug.get(slug);
72
+ propertySpecBySlug.set(slug, Array.isArray(existingIds) ? [...existingIds, ...idsArray] : idsArray);
72
73
  continue;
73
74
  }
74
75
  const existing = propertySpecBySlug.get(slug);
@@ -190,6 +190,11 @@ describe('parsePropertySpecificationsIntoMap', () => {
190
190
  expect(result.get('ids')).toEqual(['1', '2', '3']);
191
191
  expect(result.get('name')).toBe('Test');
192
192
  });
193
+ it('should accumulate repeated ids keys', () => {
194
+ const specs = ['ids=1,2', 'ids=3'];
195
+ const result = (0, propertySpecifications_1.parsePropertySpecificationsIntoMap)(specs);
196
+ expect(result.get('ids')).toEqual(['1', '2', '3']);
197
+ });
193
198
  it('should handle ids as single value', () => {
194
199
  const specs = ['ids=123'];
195
200
  const result = (0, propertySpecifications_1.parsePropertySpecificationsIntoMap)(specs);
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "3.6.0-alpha-8-alpha.19e980d",
2
+ "version": "3.6.0-alpha-8-alpha.828359d",
3
3
  "commands": {
4
4
  "app:create": {
5
5
  "id": "app:create",
@@ -1077,7 +1077,7 @@
1077
1077
  "name": "dryRun",
1078
1078
  "type": "boolean",
1079
1079
  "char": "d",
1080
- "description": "If true, does not create the entity but simulates the creation",
1080
+ "description": "If true, does not update the entities but simulates the update",
1081
1081
  "required": false,
1082
1082
  "allowNo": false
1083
1083
  },
@@ -1085,18 +1085,10 @@
1085
1085
  "name": "inputFile",
1086
1086
  "type": "option",
1087
1087
  "char": "i",
1088
- "description": "File containing properties to update the entity (optional)",
1088
+ "description": "A file with a JSON array of {id, ...} objects; each object is one entity to update.",
1089
1089
  "required": false,
1090
1090
  "multiple": false
1091
1091
  },
1092
- "force": {
1093
- "name": "force",
1094
- "type": "boolean",
1095
- "char": "F",
1096
- "description": "Force update without validation. Internal use only",
1097
- "required": false,
1098
- "allowNo": false
1099
- },
1100
1092
  "suffix": {
1101
1093
  "name": "suffix",
1102
1094
  "type": "option",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrail/cli",
3
- "version": "3.6.0-alpha-8-alpha.19e980d",
3
+ "version": "3.6.0-alpha-8-alpha.828359d",
4
4
  "description": "VibeIQ's Contrail Platform CLI.",
5
5
  "bin": {
6
6
  "contrail-cli": "./bin/run",