contensis-cli 1.4.1 → 1.4.2-beta.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.
Files changed (51) hide show
  1. package/README.md +360 -1
  2. package/dist/commands/create.js +83 -2
  3. package/dist/commands/create.js.map +2 -2
  4. package/dist/commands/get.js +33 -1
  5. package/dist/commands/get.js.map +2 -2
  6. package/dist/commands/import.js +62 -0
  7. package/dist/commands/import.js.map +2 -2
  8. package/dist/commands/list.js +48 -1
  9. package/dist/commands/list.js.map +2 -2
  10. package/dist/commands/remove.js +50 -1
  11. package/dist/commands/remove.js.map +2 -2
  12. package/dist/localisation/en-GB.js +38 -8
  13. package/dist/localisation/en-GB.js.map +2 -2
  14. package/dist/providers/HttpProvider.js +4 -4
  15. package/dist/providers/HttpProvider.js.map +2 -2
  16. package/dist/providers/ManifestProvider.js +2 -2
  17. package/dist/providers/ManifestProvider.js.map +2 -2
  18. package/dist/providers/SessionCacheProvider.js +6 -3
  19. package/dist/providers/SessionCacheProvider.js.map +2 -2
  20. package/dist/providers/file-provider.js +2 -2
  21. package/dist/providers/file-provider.js.map +2 -2
  22. package/dist/services/ContensisCliService.js +370 -22
  23. package/dist/services/ContensisCliService.js.map +3 -3
  24. package/dist/shell.js +14 -1
  25. package/dist/shell.js.map +2 -2
  26. package/dist/util/assert.js +62 -0
  27. package/dist/util/assert.js.map +7 -0
  28. package/dist/util/index.js +11 -36
  29. package/dist/util/index.js.map +2 -2
  30. package/dist/util/logger.js +17 -6
  31. package/dist/util/logger.js.map +2 -2
  32. package/dist/version.js +1 -1
  33. package/dist/version.js.map +1 -1
  34. package/package.json +2 -2
  35. package/src/commands/create.ts +118 -0
  36. package/src/commands/get.ts +48 -1
  37. package/src/commands/import.ts +86 -0
  38. package/src/commands/list.ts +80 -1
  39. package/src/commands/remove.ts +91 -1
  40. package/src/localisation/en-GB.ts +62 -9
  41. package/src/models/Cache.d.ts +2 -1
  42. package/src/providers/HttpProvider.ts +1 -1
  43. package/src/providers/ManifestProvider.ts +1 -1
  44. package/src/providers/SessionCacheProvider.ts +6 -1
  45. package/src/providers/file-provider.ts +1 -1
  46. package/src/services/ContensisCliService.ts +480 -24
  47. package/src/shell.ts +14 -1
  48. package/src/util/assert.ts +35 -0
  49. package/src/util/index.ts +15 -36
  50. package/src/util/logger.ts +18 -6
  51. package/src/version.ts +1 -1
@@ -1,7 +1,9 @@
1
1
  import { Command } from 'commander';
2
2
  import { Project } from 'contensis-core-api';
3
+ import { addGlobalOptions, commit } from './globalOptions';
3
4
  import { cliCommand } from '~/services/ContensisCliService';
4
5
  import { shell } from '~/shell';
6
+ import { toApiId } from '~/util/api-ids';
5
7
 
6
8
  export const makeCreateCommand = () => {
7
9
  const create = new Command()
@@ -9,6 +11,7 @@ export const makeCreateCommand = () => {
9
11
  .description('create command')
10
12
  .addHelpText('after', `\n`)
11
13
  .showHelpAfterError(true)
14
+ .enablePositionalOptions()
12
15
  .exitOverride();
13
16
 
14
17
  create
@@ -38,6 +41,7 @@ export const makeCreateCommand = () => {
38
41
  description,
39
42
  primaryLanguage: opts.language,
40
43
  supportedLanguages: opts.supportedLanguages || [],
44
+ deliverySysExclusions: [],
41
45
  };
42
46
 
43
47
  const project = await cliCommand(
@@ -89,5 +93,119 @@ Example call:
89
93
  });
90
94
  });
91
95
 
96
+ create
97
+ .command('taggroup')
98
+ .description('create a new tag group')
99
+ .argument('<groupId>', 'the API id of the tag group to create')
100
+ .argument('<"Name">', 'the name of the tag group to create')
101
+ .argument('["Description"]', 'a description for the tag group')
102
+ .option(
103
+ '--tags <tagNames...>',
104
+ 'a list of tag names to create under the new tag group'
105
+ )
106
+ .addOption(commit)
107
+ .addHelpText(
108
+ 'after',
109
+ `
110
+ Example call:
111
+ > create taggroup example "Example tags" "This group is a test"
112
+ > create taggroup topics "Topics" --tags Books Faces History Places Spelling \n`
113
+ )
114
+ .action(
115
+ async (groupId: string, name: string, description: string, opts) => {
116
+ const tagGroup = {
117
+ id: groupId,
118
+ name,
119
+ description,
120
+ };
121
+
122
+ await cliCommand(
123
+ ['create', 'taggroup', groupId, name],
124
+ opts
125
+ ).ImportTagGroups({
126
+ commit: opts.commit,
127
+ data: [tagGroup],
128
+ tags: opts.tags?.map((label: string) => ({
129
+ groupId,
130
+ label: { 'en-GB': label },
131
+ value: toApiId(label, 'camelCase', true),
132
+ })),
133
+ });
134
+ }
135
+ );
136
+
137
+ const tags = create
138
+ .command('tags')
139
+ .description('create new tags in a tag group')
140
+ .argument('<"Label"...>', 'create tag(s) with label(s)')
141
+ .passThroughOptions()
142
+ .option('-in --group <groupId>', 'create tags in this tag group')
143
+ .addOption(commit)
144
+ .addHelpText(
145
+ 'after',
146
+ `
147
+ Example call:
148
+ > create tags "Test tag" --group example
149
+ > create tags Books Faces History Places Spelling -in topics \n`
150
+ )
151
+ .action(async (tagLabels: string[], opts) => {
152
+ const groupId = opts.group;
153
+ const cli = cliCommand(['create', 'tags', ...tagLabels], opts);
154
+
155
+ const language =
156
+ cli.env.projects.find(p => p.id === cli.env.currentProject)
157
+ ?.primaryLanguage || 'en-GB';
158
+
159
+ await cli.ImportTags({
160
+ commit: opts.commit,
161
+ data: tagLabels.map(label => ({
162
+ groupId,
163
+ label: { [language]: label },
164
+ value: toApiId(label, 'camelCase', true),
165
+ })),
166
+ });
167
+ });
168
+
169
+ tags
170
+ .command('in')
171
+ .description('create new tags in a tag group')
172
+ .argument('<groupId>', 'create tag(s) in this tag group')
173
+ .argument('<"Label"...>', 'create tag(s) with label(s)')
174
+ .addOption(commit)
175
+ .addHelpText(
176
+ 'after',
177
+ `
178
+ Example call:
179
+ > create tags in example "Tag 1" "Second Tag" Third
180
+ > create tags ih topics Books Faces History Places Spelling \n`
181
+ )
182
+ .action(async (groupId: string, tagLabels: string[], opts, cmd) => {
183
+ // workaround for opts.commit being always false
184
+ // read the (shared) options that were parsed by the parent cmd
185
+ // https://github.com/tj/commander.js/issues/476#issuecomment-1675757628
186
+ const parentOptions = cmd.optsWithGlobals();
187
+
188
+ const cli = cliCommand(['create', 'tags', 'in', groupId, ...tagLabels], {
189
+ ...opts,
190
+ ...parentOptions,
191
+ });
192
+
193
+ const language =
194
+ cli.env.projects.find(p => p.id === cli.env.currentProject)
195
+ ?.primaryLanguage || 'en-GB';
196
+
197
+ await cli.ImportTags({
198
+ commit: parentOptions.commit,
199
+ data: tagLabels.map(label => ({
200
+ groupId,
201
+ label: { [language]: label },
202
+ value: toApiId(label, 'camelCase', true),
203
+ })),
204
+ });
205
+ });
206
+
207
+ // Add global opts for inner sub-commands
208
+ addGlobalOptions(tags);
209
+
92
210
  return create;
93
211
  };
@@ -1,6 +1,5 @@
1
1
  import { Argument, Command, Option } from 'commander';
2
2
  import { merge } from 'lodash';
3
- import { cliCommand } from '~/services/ContensisCliService';
4
3
  import {
5
4
  addGlobalOptions,
6
5
  assetTypes,
@@ -15,6 +14,8 @@ import {
15
14
  versionStatus,
16
15
  zenql,
17
16
  } from './globalOptions';
17
+ import { cliCommand } from '~/services/ContensisCliService';
18
+ import { isUuid } from '~/util/assert';
18
19
 
19
20
  export const makeGetCommand = () => {
20
21
  const program = new Command()
@@ -118,6 +119,52 @@ Example call:
118
119
  );
119
120
  });
120
121
 
122
+ program
123
+ .command('tag')
124
+ .description('get a tag')
125
+ .argument('[idOrLabel]', 'find a tag with this id or label')
126
+ .option('-in --group <groupId>', 'id of the tag group containing tags')
127
+ .option('-l --language <language>', 'find tags in the supplied language')
128
+ .option('-d --dependents', 'find and return tag groups for all found tags')
129
+ .addHelpText(
130
+ 'after',
131
+ `
132
+ Example call:
133
+ > get tag "Places" --group topics
134
+ > get tag "Places" -in topics
135
+ > get tag "Lieux" --language fr-FR -in topics
136
+ > get tag d4267b35-0d25-41ae-bce9-eeb490c793f4
137
+ `
138
+ )
139
+ .action(async (idOrlabel: string, opts) => {
140
+ await cliCommand(['get', 'tag', idOrlabel], opts).PrintTag(
141
+ {
142
+ id: isUuid(idOrlabel) ? idOrlabel : undefined,
143
+ groupId: opts.group,
144
+ label: isUuid(idOrlabel) ? undefined : idOrlabel,
145
+ language: opts.language,
146
+ },
147
+ opts.dependents
148
+ );
149
+ });
150
+
151
+ program
152
+ .command('taggroup')
153
+ .description('get a tag group')
154
+ .argument('<groupId>', 'id of the tag group to get')
155
+ .addHelpText(
156
+ 'after',
157
+ `
158
+ Example call:
159
+ > get taggroup topics
160
+ `
161
+ )
162
+ .action(async (groupId: string, opts) => {
163
+ await cliCommand(['get', 'taggroup', groupId], opts).PrintTagGroup(
164
+ groupId
165
+ );
166
+ });
167
+
121
168
  program
122
169
  .command('webhook')
123
170
  .description('get a webhook')
@@ -208,6 +208,92 @@ Example call:
208
208
  });
209
209
  });
210
210
 
211
+ program
212
+ .command('taggroups')
213
+ .description('import taggroups')
214
+ .argument('[query]', 'apply a filter')
215
+ .option('-i --id <ids...>', 'limit to the supplied tag group id(s)')
216
+ .addOption(commit)
217
+ .option(
218
+ '-preserve --preserve-guids',
219
+ 'include this flag when you are importing tags that you have previously exported and wish to update'
220
+ )
221
+ .addOption(concurrency)
222
+ .addOption(ignoreErrors)
223
+ .option(
224
+ '--save',
225
+ "save the tag groups we're migrating instead of the migration preview (used with --output)"
226
+ )
227
+ .addHelpText(
228
+ 'after',
229
+ `
230
+ Example call:
231
+ > import taggroups --source-cms example-dev --source-project-id microsite --zenql "sys.contentTypeId = blog"
232
+ > import taggroups --from-file myImportData.json --preserve-guids
233
+ `
234
+ )
235
+ .action(async (query: string, opts) => {
236
+ await cliCommand(
237
+ ['import', 'taggroups'],
238
+ opts,
239
+ mapContensisOpts(opts)
240
+ ).ImportTagGroups({
241
+ commit: opts.commit,
242
+ fromFile: opts.fromFile,
243
+ getBy: {
244
+ id: opts.id?.length === 1 ? opts.id[0] : undefined,
245
+ ids: opts.id?.length > 1 ? opts.id : undefined,
246
+ q: query,
247
+ },
248
+ save: opts.save,
249
+ });
250
+ });
251
+
252
+ program
253
+ .command('tags')
254
+ .description('import tags')
255
+ .option('-in --group <groupId>', 'id of the tag group containing tags')
256
+ .option('--label <label>', 'filter by tags that match this label')
257
+ .option('-l --language <language>', 'find tags in the supplied language')
258
+ .option('-i --id <ids...>', 'limit to the supplied tag group id(s)')
259
+ .addOption(commit)
260
+ .option(
261
+ '-preserve --preserve-guids',
262
+ 'include this flag when you are importing tags that you have previously exported and wish to update'
263
+ )
264
+ .addOption(concurrency)
265
+ .addOption(ignoreErrors)
266
+ .option(
267
+ '--save',
268
+ "save the tags we're migrating instead of the migration preview (used with --output)"
269
+ )
270
+ .addHelpText(
271
+ 'after',
272
+ `
273
+ Example call:
274
+ > import tags --source-cms example-dev --source-project-id microsite --group example
275
+ > import tags --from-file myImportData.json --preserve-guids
276
+ `
277
+ )
278
+ .action(async (opts) => {
279
+ await cliCommand(
280
+ ['import', 'tags'],
281
+ opts,
282
+ mapContensisOpts(opts)
283
+ ).ImportTags({
284
+ commit: opts.commit,
285
+ fromFile: opts.fromFile,
286
+ getBy: {
287
+ groupId: opts.group,
288
+ id: opts.id?.length === 1 ? opts.id[0] : undefined,
289
+ ids: opts.id?.length > 1 ? opts.id : undefined,
290
+ label: opts.label,
291
+ language: opts.language,
292
+ },
293
+ save: opts.save,
294
+ });
295
+ });
296
+
211
297
  return program;
212
298
  };
213
299
 
@@ -1,6 +1,11 @@
1
1
  import { Command } from 'commander';
2
2
  import { cliCommand } from '~/services/ContensisCliService';
3
- import { exportOption, mapContensisOpts, noCache } from './globalOptions';
3
+ import {
4
+ addGlobalOptions,
5
+ exportOption,
6
+ mapContensisOpts,
7
+ noCache,
8
+ } from './globalOptions';
4
9
 
5
10
  export const makeListCommand = () => {
6
11
  const list = new Command()
@@ -8,6 +13,7 @@ export const makeListCommand = () => {
8
13
  .description('list command')
9
14
  .addHelpText('after', `\n`)
10
15
  .showHelpAfterError(true)
16
+ .enablePositionalOptions()
11
17
  .exitOverride();
12
18
 
13
19
  list
@@ -156,6 +162,76 @@ Example call:
156
162
  await cliCommand(['list', 'roles'], opts).PrintRoles();
157
163
  });
158
164
 
165
+ const tags = list
166
+ .command('tags')
167
+ .description('print list of tags')
168
+ .argument('[label]', 'filter by tags that match this label')
169
+ .passThroughOptions()
170
+ .option('-in --group <groupId>', 'id of the tag group containing tags')
171
+ .option('-i --id <ids...>', 'limit output to the supplied tag id(s)')
172
+ .option('-l --language <language>', 'find tags in the supplied language')
173
+ .option('-d --dependents', 'find and return tag groups for all found tags')
174
+ .addHelpText(
175
+ 'after',
176
+ `
177
+ Example call:
178
+ > list tags
179
+ `
180
+ )
181
+ .action(async (label, opts) => {
182
+ await cliCommand(['list', 'tags'], { ...opts, label }).PrintTags(
183
+ {
184
+ id: opts.id?.length === 1 ? opts.id[0] : undefined,
185
+ ids: opts.id?.length > 1 ? opts.id : undefined,
186
+ groupId: opts.group,
187
+ label,
188
+ language: opts.language,
189
+ },
190
+ opts.dependents
191
+ );
192
+ });
193
+
194
+ tags
195
+ .command('in')
196
+ .description('print list of tags in a group')
197
+ .argument('<groupId>', 'id of the tag group containing tags')
198
+ .option('--label <label>', 'filter by tags that match this label')
199
+ .option(
200
+ '-l --language <language>',
201
+ 'find tags by a label in a specific language'
202
+ )
203
+ .addHelpText(
204
+ 'after',
205
+ `
206
+ Example call:
207
+ > list tags in example
208
+ `
209
+ )
210
+ .action(async (groupId: string, opts) => {
211
+ await cliCommand(['list', 'tags', 'in'], {
212
+ ...opts,
213
+ groupId,
214
+ }).PrintTags({
215
+ ...opts,
216
+ groupId,
217
+ });
218
+ });
219
+
220
+ list
221
+ .command('taggroups')
222
+ .description('print list of tag groups')
223
+ .argument('[query]', 'filter tag groups')
224
+ .addHelpText(
225
+ 'after',
226
+ `
227
+ Example call:
228
+ > list taggroups
229
+ `
230
+ )
231
+ .action(async (query, opts) => {
232
+ await cliCommand(['list', 'taggroups'], opts).PrintTagGroups(query);
233
+ });
234
+
159
235
  list
160
236
  .command('webhooks')
161
237
  .description('print list of webhooks')
@@ -182,5 +258,8 @@ Example call:
182
258
  await cliCommand(['list', 'workflows'], opts).PrintWorkflows();
183
259
  });
184
260
 
261
+ // Add global opts for inner sub-commands
262
+ addGlobalOptions(tags);
263
+
185
264
  return list;
186
265
  };
@@ -2,7 +2,12 @@ import { Command } from 'commander';
2
2
  import { cliCommand } from '~/services/ContensisCliService';
3
3
  import { shell } from '~/shell';
4
4
  import { Logger } from '~/util/logger';
5
- import { commit, mapContensisOpts, zenql } from './globalOptions';
5
+ import {
6
+ addGlobalOptions,
7
+ commit,
8
+ mapContensisOpts,
9
+ zenql,
10
+ } from './globalOptions';
6
11
 
7
12
  export const makeRemoveCommand = () => {
8
13
  const remove = new Command()
@@ -10,6 +15,7 @@ export const makeRemoveCommand = () => {
10
15
  .description('remove command')
11
16
  .addHelpText('after', `\n`)
12
17
  .showHelpAfterError(true)
18
+ .enablePositionalOptions()
13
19
  .exitOverride();
14
20
 
15
21
  remove
@@ -175,5 +181,89 @@ Example call:
175
181
  ).RemoveNodes(opts.commit);
176
182
  });
177
183
 
184
+ remove
185
+ .command('taggroup')
186
+ .description('delete an unused tag group')
187
+ .argument('<groupId>', 'id of the tag group to remove')
188
+ .addOption(commit)
189
+ .addHelpText(
190
+ 'after',
191
+ `
192
+ Example call:
193
+ > remove taggroup example
194
+ `
195
+ )
196
+ .action(async (groupId: string, opts) => {
197
+ await cliCommand(['remove', 'taggroup', groupId], opts).RemoveTagGroup(
198
+ groupId,
199
+ opts.commit
200
+ );
201
+ });
202
+
203
+ const tags = remove
204
+ .command('tags')
205
+ .description('delete unused tags')
206
+ .passThroughOptions()
207
+ .argument('[ids...]', 'id(s) of the tag(s) to remove')
208
+ .option('--all', 'delete all tags')
209
+ .addOption(commit)
210
+ .addHelpText(
211
+ 'after',
212
+ `
213
+ Example call:
214
+ > remove tags d4267b35-0d25-41ae-bce9-eeb490c793f4 90a11d09-3727-45c2-a0df-86f1865828ab
215
+ > remove tags --all
216
+
217
+ `
218
+ )
219
+ .action(async (ids: string[], opts, cmd: Command) => {
220
+ if ((!ids || !ids.length) && !opts.all)
221
+ cmd.error('Missing one of the required options');
222
+
223
+ await cliCommand(['remove', 'tags', ...ids], opts).RemoveTags(
224
+ { ids: ids.length ? ids : undefined },
225
+ opts.commit
226
+ );
227
+ });
228
+
229
+ tags
230
+ .command('in')
231
+ .description('delete unused tags in a specific tag group')
232
+ .showHelpAfterError(true)
233
+ .argument('<groupId>', 'id of the tag group containing tags')
234
+ .option('--all', 'delete all tags in this group')
235
+ .option('--label <label>', 'delete tags that match this label')
236
+ .option(
237
+ '-l --language <language>',
238
+ 'delete tags by a label in a specific language'
239
+ )
240
+ .addOption(commit)
241
+ .addHelpText(
242
+ 'after',
243
+ `
244
+ Example call:
245
+ > remove tags in example --label Test
246
+ > remove tags in example --all
247
+
248
+ `
249
+ )
250
+ .action(async (groupId: string, opts, cmd: Command) => {
251
+ // workaround for opts.commit being always false
252
+ // read the (shared) options that were parsed by the parent cmd
253
+ // https://github.com/tj/commander.js/issues/476#issuecomment-1675757628
254
+ const parentOptions = cmd.optsWithGlobals();
255
+
256
+ if (!parentOptions.all && !opts.label)
257
+ cmd.error('Missing one of the required options');
258
+
259
+ await cliCommand(['remove', 'tags', 'in', groupId], opts).RemoveTags(
260
+ { groupId, ...opts, ...parentOptions },
261
+ parentOptions.commit
262
+ );
263
+ });
264
+
265
+ // Add global opts for inner sub-commands
266
+ addGlobalOptions(tags);
267
+
178
268
  return remove;
179
269
  };
@@ -115,8 +115,18 @@ export const LogMessages = {
115
115
  `[${env}] Unable to update project ${Logger.highlightText(id)}`,
116
116
  },
117
117
  migrate: {
118
+ commitTip: () => `Add --commit flag to commit the previewed changes`,
118
119
  preview: (verb = 'IMPORT') => `🔍 ${verb} PREVIEW 🔭`,
119
120
  commit: (verb = 'IMPORT') => `COMMITTING ${verb} ✨☄️ `,
121
+ imported: (
122
+ env: string,
123
+ commit: boolean,
124
+ entities: { [noun: string]: number }
125
+ ) =>
126
+ `${commit ? `Imported` : `Will import`} ${Object.entries(entities)
127
+ .map(([noun, count]) => pl(noun, count, true))
128
+ .join(' and ')} into ${env} environment`,
129
+
120
130
  models: {
121
131
  result: (
122
132
  status: keyof MigrateModelsResult['project']['contentTypes']
@@ -161,11 +171,7 @@ export const LogMessages = {
161
171
  },
162
172
  nodes: {
163
173
  imported: (env: string, commit: boolean, count: number) =>
164
- `[${env}] ${commit ? `Imported` : `Will import`} ${pl(
165
- 'node',
166
- count,
167
- true
168
- )}`,
174
+ LogMessages.migrate.imported(env, commit, { node: count }),
169
175
  failedImport: (env: string) => `[${env}] Unable to import nodes`,
170
176
  removed: (env: string, commit: boolean, root: string) =>
171
177
  `[${env}] ${commit ? `Deleted` : `Will delete`} nodes at ${root}`,
@@ -222,9 +228,10 @@ export const LogMessages = {
222
228
  },
223
229
  entries: {
224
230
  imported: (env: string, commit: boolean, entries: number, nodes = 0) =>
225
- `${commit ? `Imported` : `Will import`} ${pl('entry', entries, true)}${
226
- nodes > 0 ? ` and ${pl('node', nodes, true)}` : ''
227
- } into ${env} environment`,
231
+ LogMessages.migrate.imported(env, commit, {
232
+ entry: entries,
233
+ node: nodes,
234
+ }),
228
235
  failedImport: (env: string) => `[${env}] Unable to import entries`,
229
236
  update: {
230
237
  preview: () => LogMessages.migrate.preview('UPDATE FIELD'),
@@ -239,7 +246,6 @@ export const LogMessages = {
239
246
  `[${env}] ${commit ? `Deleted` : `Will delete`} entries`,
240
247
  failedRemove: (env: string) => `[${env}] Unable to delete entries`,
241
248
  notFound: (env: string) => `[${env}] Entries were not found`,
242
- commitTip: () => `Add --commit flag to commit the previewed changes`,
243
249
  },
244
250
  keys: {
245
251
  list: (env: string) => `[${env}] API keys:`,
@@ -344,6 +350,53 @@ export const LogMessages = {
344
350
  failedRemove: (env: string, id: string) =>
345
351
  `[${env}] Unable to delete role ${Logger.highlightText(id)}`,
346
352
  },
353
+ taggroups: {
354
+ list: (env: string, length: number) =>
355
+ `[${env}] Retrieved ${pl('tag group', length, true)}`,
356
+ noList: (env: string) => `[${env}] Cannot retrieve tag groups`,
357
+ noneExist: () => `Create a tag group with "create taggroup <name>"`,
358
+ imported: (env: string, commit: boolean, groups: number, tags: number) =>
359
+ LogMessages.migrate.imported(env, commit, {
360
+ 'tag group': groups,
361
+ tag: tags,
362
+ }),
363
+ failedGet: (env: string, name: string) =>
364
+ `[${env}] Unable to find a tag group ${Logger.highlightText(name)}`,
365
+ created: (env: string, name: string) =>
366
+ `[${env}] Created tag group ${Logger.highlightText(name)}\n`,
367
+ tip: () =>
368
+ `Give access to your role with "set role assignments", allow your role to do things with "set role permissions"`,
369
+ failedCreate: (env: string, name?: string) =>
370
+ `[${env}] Unable to create ${name ? `tag group ${Logger.highlightText(name)}` : 'tag groups'}`,
371
+ removed: (env: string, id: string, commit: boolean) =>
372
+ `[${env}] ${
373
+ commit ? `Deleted` : `Will delete`
374
+ } tag group ${Logger.highlightText(id)}\n`,
375
+ failedRemove: (env: string, id: string) =>
376
+ `[${env}] Unable to delete tag group ${Logger.highlightText(id)}`,
377
+ },
378
+ tags: {
379
+ list: (env: string, length: number) =>
380
+ `[${env}] Retrieved ${pl('tag', length, true)}`,
381
+ noList: (env: string) => `[${env}] Cannot retrieve tags`,
382
+ noneExist: () =>
383
+ `Create a tag with "create tag in <groupId> <tag label(s)...>"`,
384
+ imported: (env: string, commit: boolean, tags: number) =>
385
+ LogMessages.migrate.imported(env, commit, { tag: tags }),
386
+ failedGet: (env: string) => `[${env}] Unable to find tags`,
387
+ created: (env: string, name: string) =>
388
+ `[${env}] Created tag ${Logger.highlightText(name)}\n`,
389
+ failedCreate: (env: string, name?: string) =>
390
+ `[${env}] Unable to create ${name ? `tag ${Logger.highlightText(name)}` : 'tags'}`,
391
+ removed: (env: string, length: number, commit: boolean) =>
392
+ `[${env}] ${
393
+ !length
394
+ ? 'No tags to delete'
395
+ : `${commit ? `Deleted` : `Will delete`} ${pl('tag', length, true)}\n`
396
+ }`,
397
+ failedRemove: (env: string, length: number) =>
398
+ `[${env}] Unable to delete tags with ${pl('error', length)}`,
399
+ },
347
400
  blocks: {
348
401
  runningStatus: (status: BlockRunningStatus | 'broken') => {
349
402
  switch (status) {
@@ -5,6 +5,7 @@ type SessionCache = {
5
5
  [alias: string]: EnvironmentCache;
6
6
  };
7
7
  history: string[];
8
+ version: string;
8
9
  };
9
10
 
10
11
  type EnvironmentCache = {
@@ -12,7 +13,7 @@ type EnvironmentCache = {
12
13
  passwordFallback?: string;
13
14
  authToken?: string;
14
15
  currentProject?: string;
15
- projects: string[];
16
+ projects: { id: string; primaryLanguage: string }[];
16
17
  history: CliCommand[];
17
18
  versionStatus: 'latest' | 'published';
18
19
  };
@@ -4,7 +4,7 @@ import fs from 'fs';
4
4
  import { Readable } from 'stream';
5
5
  import { finished } from 'stream/promises';
6
6
 
7
- import { isJson, tryParse } from '~/util';
7
+ import { isJson, tryParse } from '~/util/assert';
8
8
  import { enhancedFetch } from '~/util/fetch';
9
9
  class HttpProvider {
10
10
  constructor() {}
@@ -1,4 +1,4 @@
1
- import { tryParse } from '~/util';
1
+ import { tryParse } from '~/util/assert';
2
2
  import { appPath, readFile, writeFile } from './file-provider';
3
3
 
4
4
  export type CliModule = {
@@ -4,8 +4,9 @@ import clone from 'lodash/cloneDeep';
4
4
  import mergeWith from 'lodash/mergeWith';
5
5
  import unionBy from 'lodash/unionBy';
6
6
  import { appRootDir, checkDir } from './file-provider';
7
- import { isJson, tryParse } from '~/util';
7
+ import { isJson, tryParse } from '~/util/assert';
8
8
  import { Logger } from '~/util/logger';
9
+ import { LIB_VERSION } from '~/version';
9
10
 
10
11
  class SessionCacheProvider {
11
12
  private localFilePath: string;
@@ -18,6 +19,7 @@ class SessionCacheProvider {
18
19
  currentTimestamp: new Date().toISOString(),
19
20
  environments: {},
20
21
  history: [],
22
+ version: LIB_VERSION,
21
23
  };
22
24
  this.ReadCacheFromDisk();
23
25
  }
@@ -64,7 +66,10 @@ class SessionCacheProvider {
64
66
 
65
67
  if (Array.isArray(val)) return val.concat(src);
66
68
  });
69
+
67
70
  this.cache.currentTimestamp = new Date().toISOString();
71
+ this.cache.version = LIB_VERSION;
72
+
68
73
  this.WriteCacheToDisk();
69
74
  } catch (ex: any) {
70
75
  // Problem merging cache data for update