contensis-cli 1.3.1-beta.0 → 1.3.1-beta.10

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 (112) hide show
  1. package/README.md +78 -6
  2. package/dist/commands/copy.js +2 -2
  3. package/dist/commands/copy.js.map +2 -2
  4. package/dist/commands/create.js +1 -2
  5. package/dist/commands/create.js.map +1 -1
  6. package/dist/commands/globalOptions.js +16 -4
  7. package/dist/commands/globalOptions.js.map +2 -2
  8. package/dist/commands/import.js +1 -1
  9. package/dist/commands/import.js.map +2 -2
  10. package/dist/commands/index.js +4 -2
  11. package/dist/commands/index.js.map +2 -2
  12. package/dist/commands/list.js.map +1 -1
  13. package/dist/commands/login.js +1 -2
  14. package/dist/commands/login.js.map +1 -1
  15. package/dist/commands/push.js +102 -10
  16. package/dist/commands/push.js.map +3 -3
  17. package/dist/commands/remove.js +15 -4
  18. package/dist/commands/remove.js.map +2 -2
  19. package/dist/commands/set.js +2 -4
  20. package/dist/commands/set.js.map +1 -1
  21. package/dist/commands/update.js +70 -0
  22. package/dist/commands/update.js.map +7 -0
  23. package/dist/factories/RequestHandlerFactory.js +12 -5
  24. package/dist/factories/RequestHandlerFactory.js.map +2 -2
  25. package/dist/index.js +4 -0
  26. package/dist/index.js.map +1 -1
  27. package/dist/localisation/en-GB.js +19 -2
  28. package/dist/localisation/en-GB.js.map +2 -2
  29. package/dist/mappers/ContensisCliService-to-RequestHanderSiteConfigYaml.js.map +1 -1
  30. package/dist/mappers/DevInit-to-CIWorkflow.js +11 -6
  31. package/dist/mappers/DevInit-to-CIWorkflow.js.map +1 -1
  32. package/dist/mappers/DevRequests-to-RequestHanderCliArgs.js +4 -2
  33. package/dist/mappers/DevRequests-to-RequestHanderCliArgs.js.map +1 -1
  34. package/dist/models/CliService.d.js.map +1 -1
  35. package/dist/providers/CredentialProvider.js +11 -4
  36. package/dist/providers/CredentialProvider.js.map +2 -2
  37. package/dist/providers/GitHubCliModuleProvider.js +8 -10
  38. package/dist/providers/GitHubCliModuleProvider.js.map +1 -1
  39. package/dist/providers/HttpProvider.js +5 -4
  40. package/dist/providers/HttpProvider.js.map +1 -1
  41. package/dist/providers/ManifestProvider.js +1 -4
  42. package/dist/providers/ManifestProvider.js.map +1 -1
  43. package/dist/providers/SessionCacheProvider.js +26 -8
  44. package/dist/providers/SessionCacheProvider.js.map +2 -2
  45. package/dist/providers/file-provider.js +13 -11
  46. package/dist/providers/file-provider.js.map +1 -1
  47. package/dist/services/ContensisAuthService.js +1 -2
  48. package/dist/services/ContensisAuthService.js.map +1 -1
  49. package/dist/services/ContensisCliService.js +194 -127
  50. package/dist/services/ContensisCliService.js.map +3 -3
  51. package/dist/services/ContensisDevService.js +15 -18
  52. package/dist/services/ContensisDevService.js.map +2 -2
  53. package/dist/services/ContensisRoleService.js +8 -10
  54. package/dist/services/ContensisRoleService.js.map +1 -1
  55. package/dist/shell.js +31 -15
  56. package/dist/shell.js.map +2 -2
  57. package/dist/util/api-ids.js.map +1 -1
  58. package/dist/util/console.printer.js +15 -17
  59. package/dist/util/console.printer.js.map +2 -2
  60. package/dist/util/csv.formatter.js +8 -15
  61. package/dist/util/csv.formatter.js.map +2 -2
  62. package/dist/util/diff.js +6 -4
  63. package/dist/util/diff.js.map +1 -1
  64. package/dist/util/dotenv.js +1 -2
  65. package/dist/util/dotenv.js.map +1 -1
  66. package/dist/util/error.js.map +1 -1
  67. package/dist/util/fetch.js +4 -0
  68. package/dist/util/fetch.js.map +1 -1
  69. package/dist/util/git.js +8 -8
  70. package/dist/util/git.js.map +1 -1
  71. package/dist/util/gitignore.js +4 -0
  72. package/dist/util/gitignore.js.map +1 -1
  73. package/dist/util/html.formatter.js +70 -0
  74. package/dist/util/html.formatter.js.map +7 -0
  75. package/dist/util/index.js +5 -1
  76. package/dist/util/index.js.map +2 -2
  77. package/dist/util/json.formatter.js +6 -4
  78. package/dist/util/json.formatter.js.map +1 -1
  79. package/dist/util/logger.js +47 -53
  80. package/dist/util/logger.js.map +2 -2
  81. package/dist/util/os.js +4 -0
  82. package/dist/util/os.js.map +1 -1
  83. package/dist/util/xml.formatter.js +4 -0
  84. package/dist/util/xml.formatter.js.map +1 -1
  85. package/dist/util/yaml.js +1 -2
  86. package/dist/util/yaml.js.map +1 -1
  87. package/dist/version.js +1 -1
  88. package/dist/version.js.map +1 -1
  89. package/esbuild.config.js +12 -16
  90. package/package.json +31 -32
  91. package/src/commands/copy.ts +3 -1
  92. package/src/commands/globalOptions.ts +10 -3
  93. package/src/commands/import.ts +2 -0
  94. package/src/commands/index.ts +4 -0
  95. package/src/commands/push.ts +125 -1
  96. package/src/commands/remove.ts +20 -0
  97. package/src/commands/update.ts +84 -0
  98. package/src/factories/RequestHandlerFactory.ts +1 -1
  99. package/src/localisation/en-GB.ts +16 -1
  100. package/src/models/CliService.d.ts +1 -1
  101. package/src/providers/CredentialProvider.ts +2 -2
  102. package/src/providers/SessionCacheProvider.ts +26 -2
  103. package/src/services/ContensisCliService.ts +187 -49
  104. package/src/services/ContensisDevService.ts +2 -2
  105. package/src/shell.ts +20 -9
  106. package/src/util/console.printer.ts +23 -19
  107. package/src/util/csv.formatter.ts +1 -1
  108. package/src/util/html.formatter.ts +52 -0
  109. package/src/util/index.ts +1 -1
  110. package/src/util/logger.ts +17 -16
  111. package/src/version.ts +1 -1
  112. package/tsconfig.json +1 -1
@@ -16,6 +16,7 @@ export const mapContensisOpts = (opts: any = {}): MigrateRequest => ({
16
16
  : undefined,
17
17
  models: opts.modelIds,
18
18
  copyField: opts.copyField,
19
+ updateField: opts.updateField,
19
20
  // convert various cli options into MigrateRequest.query format
20
21
  query:
21
22
  opts.id ||
@@ -49,6 +50,7 @@ export const mapContensisOpts = (opts: any = {}): MigrateRequest => ({
49
50
  noCache: !opts.cache, // arg is inverted automatically from `--no-cache` to `cache: false`
50
51
  includeDefaults: opts.defaults, // arg is inverted automatically from `--no-defaults` to `defaults: false`
51
52
  concurrency: opts.concurrency ? Number(opts.concurrency) : undefined,
53
+ noPublish: !opts.publish, // arg is inverted automatically from `--no-publish` to `publish: false`
52
54
  });
53
55
 
54
56
  /* Output options */
@@ -59,8 +61,8 @@ const output = new Option(
59
61
 
60
62
  const format = new Option(
61
63
  '-f --format <format>',
62
- 'format output as csv, json, xml or table (default)'
63
- ).choices(['csv', 'json', 'xml', 'table']);
64
+ 'format output as csv, json, html, xml or default'
65
+ ).choices(['csv', 'json', 'html', 'xml', 'table']);
64
66
 
65
67
  /* Connect options */
66
68
  const alias = new Option(
@@ -177,7 +179,12 @@ export const concurrency = new Option(
177
179
 
178
180
  export const noCache = new Option(
179
181
  '--no-cache',
180
- 'add this flag to ignore internal cache and rebuild all resources from scratch'
182
+ 'ignore internal cache and rebuild all resources from scratch'
183
+ );
184
+
185
+ export const noPublish = new Option(
186
+ '--no-publish',
187
+ "don't publish created or updated entries"
181
188
  );
182
189
 
183
190
  export const addConnectOptions = (program: Command) =>
@@ -10,6 +10,7 @@ import {
10
10
  latest,
11
11
  mapContensisOpts,
12
12
  noCache,
13
+ noPublish,
13
14
  outputDetail,
14
15
  saveEntries,
15
16
  versionStatus,
@@ -139,6 +140,7 @@ Example call:
139
140
  .addOption(outputDetail)
140
141
  .addOption(ignoreErrors)
141
142
  .addOption(noCache)
143
+ .addOption(noPublish)
142
144
  .addOption(saveEntries)
143
145
  .addHelpText(
144
146
  'after',
@@ -20,6 +20,7 @@ import { makeLoginCommand } from './login';
20
20
  import { makePushCommand } from './push';
21
21
  import { makeRemoveCommand } from './remove';
22
22
  import { makeSetCommand } from './set';
23
+ import { makeUpdateCommand } from './update';
23
24
 
24
25
  const commands = () => {
25
26
  const program = new Command()
@@ -89,6 +90,9 @@ const commands = () => {
89
90
  program.addCommand(
90
91
  addConnectOptions(makeSetCommand()).copyInheritedSettings(program)
91
92
  );
93
+ program.addCommand(
94
+ addGlobalOptions(makeUpdateCommand()).copyInheritedSettings(program)
95
+ );
92
96
 
93
97
  return program;
94
98
  };
@@ -1,7 +1,18 @@
1
1
  import { Command } from 'commander';
2
2
  import mapJson from 'jsonpath-mapper';
3
- import { PushBlockParams } from 'migratortron';
3
+ import { generateGuid, PushBlockParams } from 'migratortron';
4
+ import path from 'path';
5
+ import { Asset } from 'contensis-delivery-api';
4
6
  import { cliCommand } from '~/services/ContensisCliService';
7
+ import {
8
+ commit,
9
+ mapContensisOpts,
10
+ noPublish,
11
+ outputDetail,
12
+ saveEntries,
13
+ } from './globalOptions';
14
+ import { jsonFormatter } from '~/util/json.formatter';
15
+ import { cwdPath } from '~/providers/file-provider';
5
16
 
6
17
  export const makePushCommand = () => {
7
18
  const push = new Command()
@@ -11,6 +22,119 @@ export const makePushCommand = () => {
11
22
  .showHelpAfterError(true)
12
23
  .exitOverride();
13
24
 
25
+ push
26
+ .command('asset')
27
+ .description('push an asset')
28
+ .argument('<content-type-id>', 'the content type id of the asset to push')
29
+ .argument(
30
+ '<title>',
31
+ 'the title of the asset as it appears in the cms (use quotes)'
32
+ )
33
+ .argument(
34
+ '[description]',
35
+ 'the description or altText of the asset (use quotes)'
36
+ )
37
+ .option(
38
+ '-from --from-file <fromFile>',
39
+ 'the local file path of the source asset'
40
+ )
41
+ .option('-url --from-url <fromUrl>', 'the full url of the source asset')
42
+ .option(
43
+ '-to --target-file-path <targetFilePath>',
44
+ 'the file path in the cms project to push the asset to e.g. "/asset-library/"'
45
+ )
46
+ .option(
47
+ '-name --target-file-name <targetFileName>',
48
+ 'set the file name in the cms project'
49
+ )
50
+ .option('-i --id <id>', 'push the asset with a specific guid')
51
+ .addOption(commit)
52
+ .addOption(noPublish)
53
+ .addOption(outputDetail)
54
+ .addOption(saveEntries)
55
+ .usage('<content-type-id> <title> [description] [options]')
56
+ .addHelpText(
57
+ 'after',
58
+ `
59
+ Example call:
60
+ > push asset pdf "Example file" "An example of a PDF asset" --from-file example.pdf --target-file-path /asset-library/pdf/\n`
61
+ )
62
+ .action(
63
+ async (
64
+ contentTypeId: string,
65
+ title: string,
66
+ description: string,
67
+ opts
68
+ ) => {
69
+ const cli = cliCommand(
70
+ ['push', 'asset', contentTypeId, title, description],
71
+ opts,
72
+ mapContensisOpts({ preserveGuids: true, ...opts, id: undefined })
73
+ );
74
+ const mapSourceVars = {
75
+ contentTypeId,
76
+ title,
77
+ description,
78
+ ...opts,
79
+ };
80
+
81
+ const assetEntry: Asset = mapJson(mapSourceVars, {
82
+ entryTitle: 'title',
83
+ title: 'title',
84
+ entryDescription: 'description',
85
+ description: 'description',
86
+ altText: ({ contentTypeId, description }) =>
87
+ contentTypeId === 'image' ? description : undefined,
88
+ sys: {
89
+ dataFormat: () => 'asset',
90
+ contentTypeId: 'contentTypeId',
91
+ id: 'id',
92
+ isPublished: () => true, // can be overridden by !opts.publish
93
+ properties: {
94
+ filename: {
95
+ $path: ['targetFileName', 'fromFile', 'fromUrl'],
96
+ $formatting: (nameOrPath: string) => {
97
+ return path.basename(nameOrPath);
98
+ },
99
+ },
100
+ filePath: {
101
+ $path: 'targetFilePath',
102
+ $default: (_, { fromFile, fromUrl }) => {
103
+ const toPosixPath = (windowsPath: string) =>
104
+ windowsPath.replace(/^(\w):|\\+/g, '/$1');
105
+
106
+ return path.dirname(
107
+ toPosixPath(fromFile || fromUrl.split(':/')[1])
108
+ );
109
+ },
110
+ },
111
+ },
112
+ uri: {
113
+ $path: ['fromFile', 'fromUrl'],
114
+ $formatting: (from: string) =>
115
+ from?.startsWith('http') ? from : cwdPath(from),
116
+ },
117
+ },
118
+ });
119
+
120
+ if (!assetEntry.sys.id)
121
+ assetEntry.sys.id = generateGuid(
122
+ cli.currentEnv,
123
+ cli.currentProject,
124
+ `${assetEntry.sys.contentTypeId}-${assetEntry.sys.properties.filePath.replaceAll('/', '').toLowerCase()}-${assetEntry.sys.properties.filename.toLowerCase()}`
125
+ );
126
+
127
+ console.log(jsonFormatter(assetEntry));
128
+
129
+ await cli.ImportEntries({
130
+ commit: opts.commit,
131
+ logOutput: opts.outputDetail,
132
+ saveEntries: opts.saveEntries,
133
+ data: [assetEntry],
134
+ });
135
+ }
136
+ );
137
+
14
138
  push
15
139
  .command('block')
16
140
  .description('push a block')
@@ -12,6 +12,26 @@ export const makeRemoveCommand = () => {
12
12
  .showHelpAfterError(true)
13
13
  .exitOverride();
14
14
 
15
+ remove
16
+ .command('env')
17
+ .description('Remove a previously connected environment from the CLI')
18
+ .argument('<alias>', 'the Contensis Cloud alias to remove')
19
+ .usage('<alias>')
20
+ .addHelpText(
21
+ 'after',
22
+ `
23
+ Example call:
24
+ > remove env ludlow-uni-dev
25
+ `
26
+ )
27
+ .action(async (alias: string, opts) => {
28
+ const currentEnvironment = await cliCommand(
29
+ ['remove', 'env', alias],
30
+ opts
31
+ ).RemoveEnvironment(alias);
32
+ if (!currentEnvironment) await shell().restart();
33
+ });
34
+
15
35
  remove
16
36
  .command('project')
17
37
  .description('remove an entire project')
@@ -0,0 +1,84 @@
1
+ import { Command } from 'commander';
2
+ import { UpdateField } from 'migratortron';
3
+ import { cliCommand } from '~/services/ContensisCliService';
4
+ import {
5
+ commit,
6
+ concurrency,
7
+ entryId,
8
+ ignoreErrors,
9
+ latest,
10
+ mapContensisOpts,
11
+ noCache,
12
+ noPublish,
13
+ outputDetail,
14
+ saveEntries,
15
+ versionStatus,
16
+ zenql,
17
+ } from './globalOptions';
18
+
19
+ export const makeUpdateCommand = () => {
20
+ const update = new Command()
21
+ .command('update')
22
+ .description('update command')
23
+ .addHelpText('after', `\n`)
24
+ .showHelpAfterError(true)
25
+ .exitOverride();
26
+
27
+ update
28
+ .command('field')
29
+ .description('find and replace within entry fields')
30
+ .argument('<fieldId>', 'the id of the field to update')
31
+ .argument(
32
+ '<find>',
33
+ 'the string to find within each entry/field (surround a phrase in double quotes)'
34
+ )
35
+ .argument(
36
+ '<replace>',
37
+ 'the string to replace with (surround a phrase in double quotes)'
38
+ )
39
+ .addOption(commit)
40
+ .addOption(concurrency)
41
+ .addOption(ignoreErrors)
42
+ .addOption(outputDetail.default('changes'))
43
+ .addOption(noCache)
44
+ .addOption(noPublish)
45
+ .option(
46
+ '--search <phrase>',
47
+ 'get entries with the search phrase, use quotes for multiple words'
48
+ )
49
+ .addOption(entryId)
50
+ .addOption(zenql)
51
+ .addOption(latest)
52
+ .addOption(versionStatus)
53
+ .addOption(saveEntries)
54
+ .usage('<fieldId> <find> <replace> (all arguments required)')
55
+ .addHelpText(
56
+ 'after',
57
+ `
58
+ Example call:
59
+ > update field authorName "Emma Smith" "Emma Davies" --zenql "sys.contentTypeId=blog"\n`
60
+ )
61
+ .action(
62
+ async (fieldId: string, find: string, replace: string, opts: any) => {
63
+ const updateField: UpdateField = {
64
+ fieldId,
65
+ find,
66
+ replace,
67
+ };
68
+
69
+ return await cliCommand(
70
+ ['update', 'field', fieldId, find, replace],
71
+ opts,
72
+ mapContensisOpts({ updateField, ...opts })
73
+ ).UpdateEntryField({
74
+ commit: opts.commit,
75
+ fromFile: opts.fromFile,
76
+ logOutput: opts.outputDetail,
77
+ saveEntries: opts.saveEntries,
78
+ });
79
+ }
80
+ );
81
+
82
+ return update;
83
+ };
84
+
@@ -218,7 +218,7 @@ export class RequestHandlerFactory {
218
218
  const { manifest, messages, moduleInfo } = this;
219
219
 
220
220
  if (moduleInfo.install && moduleInfo.version !== moduleInfo.install) {
221
- let { apply } =
221
+ const { apply } =
222
222
  moduleInfo.version === '*'
223
223
  ? { apply: true }
224
224
  : await inquirer.prompt({
@@ -30,7 +30,11 @@ export const LogMessages = {
30
30
  },
31
31
  envs: {
32
32
  found: (num: number) =>
33
- `environments store found containing ${pl('environment', num, true)}`,
33
+ `Environments store found containing ${pl('environment', num, true)}`,
34
+ notFound: (alias: string) =>
35
+ `Environment ${Logger.highlightText(alias)} was not found in session cache`,
36
+ removed: (alias: string) =>
37
+ `Removed environment ${Logger.highlightText(alias)} from session cache`,
34
38
  tip: () =>
35
39
  `Connect to a Contensis cloud instance using "contensis connect {cms alias}"`,
36
40
  },
@@ -111,6 +115,8 @@ export const LogMessages = {
111
115
  `[${env}] Unable to update project ${Logger.highlightText(id)}`,
112
116
  },
113
117
  migrate: {
118
+ preview: (verb = 'IMPORT') => `🔍 ${verb} PREVIEW 🔭`,
119
+ commit: (verb = 'IMPORT') => `COMMITTING ${verb} ✨☄️ `,
114
120
  models: {
115
121
  result: (
116
122
  status: keyof MigrateModelsResult['project']['contentTypes']
@@ -220,6 +226,15 @@ export const LogMessages = {
220
226
  nodes > 0 ? ` and ${pl('node', nodes, true)}` : ''
221
227
  } into ${env} environment`,
222
228
  failedImport: (env: string) => `[${env}] Unable to import entries`,
229
+ update: {
230
+ preview: () => LogMessages.migrate.preview('UPDATE FIELD'),
231
+ commit: () => LogMessages.migrate.preview('FIELD UPDATES'),
232
+ success: (env: string, commit: boolean, entries: number, nodes = 0) =>
233
+ `${commit ? `Updated` : `Will update`} ${pl('entry', entries, true)}${
234
+ nodes > 0 ? ` and ${pl('node', nodes, true)}` : ''
235
+ } in ${env} environment`,
236
+ failed: (env: string) => `[${env}] Unable to update any entries`,
237
+ },
223
238
  removed: (env: string, commit: boolean) =>
224
239
  `[${env}] ${commit ? `Deleted` : `Will delete`} entries`,
225
240
  failedRemove: (env: string) => `[${env}] Unable to delete entries`,
@@ -9,7 +9,7 @@ export type CliUrls =
9
9
  }
10
10
  | undefined;
11
11
 
12
- export type OutputFormat = 'json' | 'csv' | 'xml';
12
+ export type OutputFormat = 'json' | 'csv' | 'html' | 'xml';
13
13
 
14
14
  export type OutputOptions = {
15
15
  format?: OutputFormat;
@@ -54,12 +54,12 @@ class CredentialProvider {
54
54
  }
55
55
  };
56
56
 
57
- Init = async (): Promise<[Error, CredentialProvider]> => {
57
+ Init = async (): Promise<[Error | null, CredentialProvider]> => {
58
58
  await this.Import();
59
59
 
60
60
  const [err, stored] = (await to(
61
61
  this.keytar.getPassword(this.serviceId, this.userId)
62
- )) as [Error, string];
62
+ )) as [Error | null, string];
63
63
 
64
64
  if (err && this.passwordFallback) {
65
65
  this.current = {
@@ -29,16 +29,18 @@ class SessionCacheProvider {
29
29
  } else {
30
30
  this.WriteCacheToDisk();
31
31
  }
32
- } catch (ex) {
32
+ } catch (ex: any) {
33
33
  // Problem reading or parsing cache file
34
+ Logger.error(ex);
34
35
  }
35
36
  };
36
37
 
37
38
  private WriteCacheToDisk = () => {
38
39
  try {
39
40
  fs.writeFileSync(this.localFilePath, JSON.stringify(this.cache, null, 2));
40
- } catch (ex) {
41
+ } catch (ex: any) {
41
42
  // Problem writing session cache to file
43
+ Logger.error(ex);
42
44
  }
43
45
  };
44
46
 
@@ -96,6 +98,28 @@ class SessionCacheProvider {
96
98
  }
97
99
  return this.Get();
98
100
  };
101
+
102
+ RemoveEnv = (env: string) => {
103
+ try {
104
+ const environment = this.cache.environments[env || ''];
105
+ if (environment) delete this.cache.environments[env || ''];
106
+
107
+ this.Update({
108
+ currentEnvironment:
109
+ this.cache.currentEnvironment === env
110
+ ? ''
111
+ : this.cache.currentEnvironment,
112
+ environments: this.cache.environments,
113
+ });
114
+ } catch (ex: any) {
115
+ // Problem merging cache data for update
116
+ Logger.error(
117
+ `Problem removing environment "${env}" in environments.json`
118
+ );
119
+ Logger.error(ex);
120
+ }
121
+ return this.Get();
122
+ };
99
123
  }
100
124
 
101
125
  export default SessionCacheProvider;