@pnp/cli-microsoft365 7.2.0-beta.6775e3a → 7.2.0-beta.8577f52

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 (136) hide show
  1. package/allCommands.json +1 -0
  2. package/allCommandsFull.json +1 -0
  3. package/dist/Auth.js +1 -1
  4. package/dist/Command.js +13 -6
  5. package/dist/api.js +5 -7
  6. package/dist/cli/Cli.js +97 -119
  7. package/dist/cli/timings.js +9 -0
  8. package/dist/index.js +8 -14
  9. package/dist/m365/cli/commands/config/config-set.js +13 -0
  10. package/dist/m365/commands/login.js +12 -8
  11. package/dist/m365/flow/commands/environment/environment-list.js +6 -4
  12. package/dist/m365/spfx/commands/project/DeployWorkflow.js +4 -4
  13. package/dist/m365/spfx/commands/project/project-doctor/{doctor-1.18.1-rc.0.js → doctor-1.18.1.js} +1 -1
  14. package/dist/m365/spfx/commands/project/project-doctor/doctor-1.18.2.js +21 -0
  15. package/dist/m365/spfx/commands/project/project-doctor.js +6 -3
  16. package/dist/m365/spfx/commands/project/project-github-workflow-add.js +17 -0
  17. package/dist/m365/spfx/commands/project/project-upgrade/{upgrade-1.18.1-rc.0.js → upgrade-1.18.1.js} +26 -26
  18. package/dist/m365/spfx/commands/project/project-upgrade/upgrade-1.18.2.js +53 -0
  19. package/dist/m365/spfx/commands/project/project-upgrade.js +18 -17
  20. package/dist/m365/spfx/commands/spfx-doctor.js +16 -1
  21. package/dist/m365/spo/commands/file/file-retentionlabel-ensure.js +14 -23
  22. package/dist/m365/spo/commands/file/file-retentionlabel-remove.js +19 -27
  23. package/dist/m365/spo/commands/folder/folder-retentionlabel-ensure.js +9 -29
  24. package/dist/m365/spo/commands/folder/folder-retentionlabel-remove.js +9 -28
  25. package/dist/m365/spo/commands/list/list-retentionlabel-ensure.js +27 -37
  26. package/dist/m365/spo/commands/list/list-retentionlabel-remove.js +6 -19
  27. package/dist/m365/spo/commands/listitem/listitem-batch-add.js +5 -0
  28. package/dist/m365/spo/commands/listitem/listitem-retentionlabel-ensure.js +36 -37
  29. package/dist/m365/spo/commands/listitem/listitem-retentionlabel-remove.js +36 -32
  30. package/dist/m365/spo/commands/serviceprincipal/serviceprincipal-grant-revoke.js +49 -12
  31. package/dist/m365/spo/commands/site/site-add.js +45 -12
  32. package/dist/m365/spo/commands/sitescript/sitescript-get.js +8 -2
  33. package/dist/m365/spo/commands/tenant/tenant-recyclebinitem-restore.js +19 -2
  34. package/dist/m365/teams/commands/user/user-app-remove.js +18 -5
  35. package/dist/request.js +6 -0
  36. package/dist/settingsNames.js +2 -0
  37. package/dist/utils/prompt.js +5 -1
  38. package/dist/utils/spo.js +109 -0
  39. package/docs/docs/_clisettings.mdx +2 -0
  40. package/docs/docs/cmd/aad/approleassignment/approleassignment-add.mdx +1 -1
  41. package/docs/docs/cmd/aad/approleassignment/approleassignment-list.mdx +2 -2
  42. package/docs/docs/cmd/aad/approleassignment/approleassignment-remove.mdx +1 -1
  43. package/docs/docs/cmd/aad/oauth2grant/oauth2grant-add.mdx +1 -1
  44. package/docs/docs/cmd/aad/oauth2grant/oauth2grant-list.mdx +2 -2
  45. package/docs/docs/cmd/aad/oauth2grant/oauth2grant-remove.mdx +2 -2
  46. package/docs/docs/cmd/aad/oauth2grant/oauth2grant-set.mdx +2 -2
  47. package/docs/docs/cmd/aad/policy/policy-list.mdx +1 -1
  48. package/docs/docs/cmd/aad/siteclassification/siteclassification-disable.mdx +1 -1
  49. package/docs/docs/cmd/aad/siteclassification/siteclassification-enable.mdx +1 -1
  50. package/docs/docs/cmd/aad/siteclassification/siteclassification-get.mdx +1 -1
  51. package/docs/docs/cmd/aad/siteclassification/siteclassification-set.mdx +1 -1
  52. package/docs/docs/cmd/aad/sp/sp-add.mdx +2 -2
  53. package/docs/docs/cmd/aad/sp/sp-get.mdx +2 -2
  54. package/docs/docs/cmd/aad/user/user-add.mdx +3 -3
  55. package/docs/docs/cmd/aad/user/user-guest-add.mdx +1 -1
  56. package/docs/docs/cmd/aad/user/user-set.mdx +3 -3
  57. package/docs/docs/cmd/flow/run/run-cancel.mdx +3 -0
  58. package/docs/docs/cmd/graph/changelog/changelog-list.mdx +5 -5
  59. package/docs/docs/cmd/login.mdx +1 -1
  60. package/docs/docs/cmd/onenote/notebook/notebook-list.mdx +1 -1
  61. package/docs/docs/cmd/outlook/message/message-list.mdx +1 -1
  62. package/docs/docs/cmd/outlook/message/message-move.mdx +1 -1
  63. package/docs/docs/cmd/planner/bucket/bucket-add.mdx +1 -1
  64. package/docs/docs/cmd/planner/bucket/bucket-set.mdx +1 -1
  65. package/docs/docs/cmd/planner/plan/plan-set.mdx +3 -3
  66. package/docs/docs/cmd/planner/task/task-set.mdx +1 -1
  67. package/docs/docs/cmd/purview/auditlog/auditlog-list.mdx +3 -3
  68. package/docs/docs/cmd/purview/retentionevent/retentionevent-add.mdx +1 -1
  69. package/docs/docs/cmd/purview/retentionevent/retentionevent-get.mdx +1 -1
  70. package/docs/docs/cmd/purview/retentioneventtype/retentioneventtype-add.mdx +1 -1
  71. package/docs/docs/cmd/purview/retentioneventtype/retentioneventtype-get.mdx +1 -1
  72. package/docs/docs/cmd/purview/retentioneventtype/retentioneventtype-remove.mdx +1 -1
  73. package/docs/docs/cmd/purview/retentioneventtype/retentioneventtype-set.mdx +1 -1
  74. package/docs/docs/cmd/purview/retentionlabel/retentionlabel-add.mdx +1 -1
  75. package/docs/docs/cmd/purview/sensitivitylabel/sensitivitylabel-policysettings-list.mdx +4 -4
  76. package/docs/docs/cmd/spfx/project/project-upgrade.mdx +1 -1
  77. package/docs/docs/cmd/spo/app/app-add.mdx +1 -1
  78. package/docs/docs/cmd/spo/app/app-deploy.mdx +1 -1
  79. package/docs/docs/cmd/spo/app/app-get.mdx +1 -1
  80. package/docs/docs/cmd/spo/app/app-install.mdx +1 -1
  81. package/docs/docs/cmd/spo/app/app-list.mdx +1 -1
  82. package/docs/docs/cmd/spo/app/app-remove.mdx +1 -1
  83. package/docs/docs/cmd/spo/app/app-retract.mdx +1 -1
  84. package/docs/docs/cmd/spo/app/app-uninstall.mdx +1 -1
  85. package/docs/docs/cmd/spo/app/app-upgrade.mdx +1 -1
  86. package/docs/docs/cmd/spo/contenttype/contenttype-add.mdx +1 -1
  87. package/docs/docs/cmd/spo/contenttype/contenttype-set.mdx +1 -1
  88. package/docs/docs/cmd/spo/hidedefaultthemes/hidedefaultthemes-get.mdx +1 -1
  89. package/docs/docs/cmd/spo/hidedefaultthemes/hidedefaultthemes-set.mdx +1 -1
  90. package/docs/docs/cmd/spo/serviceprincipal/serviceprincipal-grant-revoke.mdx +10 -1
  91. package/docs/docs/cmd/spo/site/site-add.mdx +25 -4
  92. package/docs/docs/cmd/spo/site/site-appcatalog-add.mdx +1 -1
  93. package/docs/docs/cmd/spo/site/site-appcatalog-remove.mdx +1 -1
  94. package/docs/docs/cmd/spo/site/site-groupify.mdx +1 -1
  95. package/docs/docs/cmd/spo/sitedesign/sitedesign-add.mdx +3 -3
  96. package/docs/docs/cmd/spo/sitedesign/sitedesign-apply.mdx +1 -1
  97. package/docs/docs/cmd/spo/sitedesign/sitedesign-get.mdx +1 -1
  98. package/docs/docs/cmd/spo/sitedesign/sitedesign-list.mdx +1 -1
  99. package/docs/docs/cmd/spo/sitedesign/sitedesign-remove.mdx +1 -1
  100. package/docs/docs/cmd/spo/sitedesign/sitedesign-rights-grant.mdx +1 -1
  101. package/docs/docs/cmd/spo/sitedesign/sitedesign-rights-list.mdx +1 -1
  102. package/docs/docs/cmd/spo/sitedesign/sitedesign-rights-revoke.mdx +1 -1
  103. package/docs/docs/cmd/spo/sitedesign/sitedesign-run-list.mdx +1 -1
  104. package/docs/docs/cmd/spo/sitedesign/sitedesign-run-status-get.mdx +1 -1
  105. package/docs/docs/cmd/spo/sitedesign/sitedesign-set.mdx +3 -3
  106. package/docs/docs/cmd/spo/sitedesign/sitedesign-task-get.mdx +1 -1
  107. package/docs/docs/cmd/spo/sitedesign/sitedesign-task-list.mdx +1 -1
  108. package/docs/docs/cmd/spo/sitedesign/sitedesign-task-remove.mdx +1 -1
  109. package/docs/docs/cmd/spo/sitescript/sitescript-add.mdx +1 -1
  110. package/docs/docs/cmd/spo/sitescript/sitescript-get.mdx +73 -3
  111. package/docs/docs/cmd/spo/sitescript/sitescript-list.mdx +1 -1
  112. package/docs/docs/cmd/spo/sitescript/sitescript-remove.mdx +1 -1
  113. package/docs/docs/cmd/spo/sitescript/sitescript-set.mdx +1 -1
  114. package/docs/docs/cmd/spo/storageentity/storageentity-get.mdx +1 -1
  115. package/docs/docs/cmd/spo/storageentity/storageentity-list.mdx +1 -1
  116. package/docs/docs/cmd/spo/storageentity/storageentity-remove.mdx +1 -1
  117. package/docs/docs/cmd/spo/storageentity/storageentity-set.mdx +1 -1
  118. package/docs/docs/cmd/spo/theme/theme-apply.mdx +1 -1
  119. package/docs/docs/cmd/spo/theme/theme-get.mdx +1 -1
  120. package/docs/docs/cmd/spo/theme/theme-list.mdx +1 -1
  121. package/docs/docs/cmd/spo/theme/theme-remove.mdx +1 -1
  122. package/docs/docs/cmd/spo/user/user-remove.mdx +1 -1
  123. package/docs/docs/cmd/spo/web/web-set.mdx +1 -1
  124. package/docs/docs/cmd/teams/channel/channel-remove.mdx +1 -1
  125. package/docs/docs/cmd/teams/meeting/meeting-get.mdx +1 -1
  126. package/docs/docs/cmd/teams/meeting/meeting-transcript-list.mdx +1 -1
  127. package/docs/docs/cmd/teams/report/report-pstncalls.mdx +1 -1
  128. package/docs/docs/cmd/teams/tab/tab-remove.mdx +1 -1
  129. package/docs/docs/cmd/teams/team/team-remove.mdx +1 -1
  130. package/docs/docs/cmd/teams/user/user-app-remove.mdx +11 -2
  131. package/docs/docs/cmd/tenant/serviceannouncement/serviceannouncement-healthissue-list.mdx +1 -1
  132. package/docs/docs/cmd/tenant/serviceannouncement/serviceannouncement-message-get.mdx +1 -1
  133. package/docs/docs/cmd/tenant/serviceannouncement/serviceannouncement-message-list.mdx +1 -1
  134. package/docs/docs/cmd/todo/task/task-set.mdx +1 -1
  135. package/npm-shrinkwrap.json +480 -516
  136. package/package.json +33 -32
package/dist/Auth.js CHANGED
@@ -341,7 +341,7 @@ export class Auth {
341
341
  const cli = Cli.getInstance();
342
342
  cli.spinner.text = response.message;
343
343
  cli.spinner.spinner = {
344
- frames: ['🌶️']
344
+ frames: ['🌶️ ']
345
345
  };
346
346
  // don't show spinner if running tests
347
347
  /* c8 ignore next 3 */
package/dist/Command.js CHANGED
@@ -78,19 +78,22 @@ class Command {
78
78
  const shouldPrompt = Cli.getInstance().getSettingWithDefaultValue(settingsNames.prompt, true);
79
79
  let prompted = false;
80
80
  for (let i = 0; i < command.options.length; i++) {
81
- if (!command.options[i].required ||
82
- typeof args.options[command.options[i].name] !== 'undefined') {
81
+ const optionInfo = command.options[i];
82
+ if (!optionInfo.required ||
83
+ typeof args.options[optionInfo.name] !== 'undefined') {
83
84
  continue;
84
85
  }
85
86
  if (!shouldPrompt) {
86
- return `Required option ${command.options[i].name} not specified`;
87
+ return `Required option ${optionInfo.name} not specified`;
87
88
  }
88
89
  if (!prompted) {
89
90
  prompted = true;
90
91
  Cli.error('🌶️ Provide values for the following parameters:');
91
92
  }
92
- const answer = await prompt.forInput({ message: `${command.options[i].name}: ` });
93
- args.options[command.options[i].name] = answer;
93
+ const answer = optionInfo.autocomplete !== undefined
94
+ ? await prompt.forSelection({ message: `${optionInfo.name}: `, choices: optionInfo.autocomplete.map((choice) => { return { name: choice, value: choice }; }) })
95
+ : await prompt.forInput({ message: `${optionInfo.name}: ` });
96
+ args.options[optionInfo.name] = answer;
94
97
  }
95
98
  if (prompted) {
96
99
  Cli.error('');
@@ -457,7 +460,11 @@ class Command {
457
460
  if (logStatement && logStatement.length > 0 && !options.query) {
458
461
  logStatement.map(l => {
459
462
  for (const x of Object.keys(l)) {
460
- if (typeof l[x] === 'object') {
463
+ // Remove object-properties from the output
464
+ // Excludes null from the check, because null is an object in JavaScript.
465
+ // Properties with null values are not removed from the output,
466
+ // as this can cause missing columns
467
+ if (typeof l[x] === 'object' && l[x] !== null) {
461
468
  delete l[x];
462
469
  }
463
470
  }
package/dist/api.js CHANGED
@@ -1,13 +1,11 @@
1
1
  import { Cli } from "./cli/Cli.js";
2
- import path from 'path';
3
- export function executeCommand(commandName, options, listener) {
2
+ export async function executeCommand(commandName, options, listener) {
4
3
  const cli = Cli.getInstance();
5
- cli.commandsFolder = path.join(__dirname, 'm365');
6
- cli.commands = [];
7
- cli.loadCommandFromArgs(commandName.split(' '));
8
- if (cli.commands.length !== 1) {
4
+ cli.loadAllCommandsInfo();
5
+ await cli.loadCommandFromArgs(commandName.split(' '));
6
+ if (!cli.commandToExecute) {
9
7
  return Promise.reject(`Command not found: ${commandName}`);
10
8
  }
11
- return Cli.executeCommandWithOutput(cli.commands[0].command, { options: options ?? {} }, listener);
9
+ return Cli.executeCommandWithOutput(cli.commandToExecute.command, { options: options ?? {} }, listener);
12
10
  }
13
11
  //# sourceMappingURL=api.js.map
package/dist/cli/Cli.js CHANGED
@@ -1,10 +1,11 @@
1
1
  import Configstore from 'configstore';
2
2
  import fs from 'fs';
3
3
  import minimist from 'minimist';
4
+ import { createRequire } from 'module';
4
5
  import ora from 'ora';
5
6
  import os from 'os';
6
7
  import path from 'path';
7
- import { pathToFileURL } from 'url';
8
+ import { fileURLToPath, pathToFileURL } from 'url';
8
9
  import Command, { CommandError } from '../Command.js';
9
10
  import config from '../config.js';
10
11
  import request from '../request.js';
@@ -12,10 +13,12 @@ import { settingsNames } from '../settingsNames.js';
12
13
  import { telemetry } from '../telemetry.js';
13
14
  import { app } from '../utils/app.js';
14
15
  import { formatting } from '../utils/formatting.js';
15
- import { fsUtil } from '../utils/fsUtil.js';
16
16
  import { md } from '../utils/md.js';
17
17
  import { validation } from '../utils/validation.js';
18
18
  import { prompt } from '../utils/prompt.js';
19
+ import { timings } from './timings.js';
20
+ const require = createRequire(import.meta.url);
21
+ const __dirname = fileURLToPath(new URL('.', import.meta.url));
19
22
  export class Cli {
20
23
  get config() {
21
24
  if (!this._config) {
@@ -34,7 +37,6 @@ export class Cli {
34
37
  }
35
38
  constructor() {
36
39
  this.commands = [];
37
- this.commandsFolder = '';
38
40
  const options = {
39
41
  text: 'Running command...',
40
42
  /* c8 ignore next 1 */
@@ -48,8 +50,11 @@ export class Cli {
48
50
  }
49
51
  return Cli.instance;
50
52
  }
51
- async execute(commandsFolder, rawArgs) {
52
- this.commandsFolder = commandsFolder;
53
+ async execute(rawArgs) {
54
+ const start = process.hrtime.bigint();
55
+ // for completion commands we also need information about commands' options
56
+ const loadAllCommandInfo = rawArgs.indexOf('completion') > -1;
57
+ this.loadAllCommandsInfo(loadAllCommandInfo);
53
58
  // check if help for a specific command has been requested using the
54
59
  // 'm365 help xyz' format. If so, remove 'help' from the array of words
55
60
  // to use lazy loading commands but keep track of the fact that help should
@@ -59,22 +64,10 @@ export class Cli {
59
64
  showHelp = true;
60
65
  rawArgs.shift();
61
66
  }
62
- // parse args to see if a command has been specified and can be loaded
63
- // rather than loading all commands
67
+ // parse args to see if a command has been specified
64
68
  const parsedArgs = minimist(rawArgs);
65
- // load commands
69
+ // load command
66
70
  await this.loadCommandFromArgs(parsedArgs._);
67
- if (this.currentCommandName) {
68
- for (let i = 0; i < this.commands.length; i++) {
69
- const command = this.commands[i];
70
- if (command.name === this.currentCommandName ||
71
- (command.aliases &&
72
- command.aliases.indexOf(this.currentCommandName) > -1)) {
73
- this.commandToExecute = command;
74
- break;
75
- }
76
- }
77
- }
78
71
  if (this.commandToExecute) {
79
72
  // we have found a command to execute. Parse args again taking into
80
73
  // account short and long options, option types and whether the command
@@ -90,6 +83,8 @@ export class Cli {
90
83
  }
91
84
  }
92
85
  else {
86
+ // we need this to properly support displaying commands
87
+ // from the current group
93
88
  this.optionsFromArgs = {
94
89
  options: parsedArgs
95
90
  };
@@ -113,26 +108,56 @@ export class Cli {
113
108
  catch (e) {
114
109
  return this.closeWithError(e, optionsWithoutShorts);
115
110
  }
111
+ const startProcessing = process.hrtime.bigint();
116
112
  try {
117
113
  // process options before passing them on to validation stage
118
114
  const contextCommandOptions = await this.loadOptionsFromContext(this.commandToExecute.options, optionsWithoutShorts.options.debug);
119
115
  optionsWithoutShorts.options = { ...contextCommandOptions, ...optionsWithoutShorts.options };
120
116
  await this.commandToExecute.command.processOptions(optionsWithoutShorts.options);
117
+ const endProcessing = process.hrtime.bigint();
118
+ timings.options.push(Number(endProcessing - startProcessing));
121
119
  }
122
120
  catch (e) {
121
+ const endProcessing = process.hrtime.bigint();
122
+ timings.options.push(Number(endProcessing - startProcessing));
123
123
  return this.closeWithError(e.message, optionsWithoutShorts, false);
124
124
  }
125
125
  // if output not specified, set the configured output value (if any)
126
126
  if (optionsWithoutShorts.options.output === undefined) {
127
127
  optionsWithoutShorts.options.output = this.getSettingWithDefaultValue(settingsNames.output, 'json');
128
128
  }
129
+ const startValidation = process.hrtime.bigint();
129
130
  const validationResult = await this.commandToExecute.command.validate(optionsWithoutShorts, this.commandToExecute);
131
+ const endValidation = process.hrtime.bigint();
132
+ timings.validation.push(Number(endValidation - startValidation));
130
133
  if (validationResult !== true) {
131
134
  return this.closeWithError(validationResult, optionsWithoutShorts, true);
132
135
  }
133
- return Cli
134
- .executeCommand(this.commandToExecute.command, optionsWithoutShorts)
135
- .then(_ => process.exit(0), err => this.closeWithError(err, optionsWithoutShorts));
136
+ const end = process.hrtime.bigint();
137
+ timings.core.push(Number(end - start));
138
+ try {
139
+ await Cli.executeCommand(this.commandToExecute.command, optionsWithoutShorts);
140
+ const endTotal = process.hrtime.bigint();
141
+ timings.total.push(Number(endTotal - start));
142
+ this.printTimings(rawArgs);
143
+ process.exit(0);
144
+ }
145
+ catch (err) {
146
+ const endTotal = process.hrtime.bigint();
147
+ timings.total.push(Number(endTotal - start));
148
+ this.printTimings(rawArgs);
149
+ await this.closeWithError(err, optionsWithoutShorts);
150
+ /* c8 ignore next */
151
+ }
152
+ }
153
+ printTimings(rawArgs) {
154
+ if (rawArgs.some(arg => arg === '--debug')) {
155
+ Cli.error('');
156
+ Cli.error('Timings:');
157
+ Object.getOwnPropertyNames(timings).forEach(key => {
158
+ Cli.error(`${key}: ${timings[key].reduce((a, b) => a + b, 0) / 1e6}ms`);
159
+ });
160
+ }
136
161
  }
137
162
  static async executeCommand(command, args) {
138
163
  const logger = {
@@ -167,6 +192,7 @@ export class Cli {
167
192
  if (showSpinner && typeof global.it === 'undefined') {
168
193
  cli.spinner.start();
169
194
  }
195
+ const startCommand = process.hrtime.bigint();
170
196
  try {
171
197
  await command.action(logger, args);
172
198
  if (args.options.debug || args.options.verbose) {
@@ -181,6 +207,8 @@ export class Cli {
181
207
  if (cli.spinner.isSpinning) {
182
208
  cli.spinner.stop();
183
209
  }
210
+ const endCommand = process.hrtime.bigint();
211
+ timings.command.push(Number(endCommand - startCommand));
184
212
  }
185
213
  }
186
214
  static async executeCommandWithOutput(command, args, listener) {
@@ -248,55 +276,26 @@ export class Cli {
248
276
  request.logger = currentLogger;
249
277
  }
250
278
  }
251
- async loadAllCommands() {
252
- const files = fsUtil.readdirR(this.commandsFolder);
253
- await Promise.all(files.map(async (filePath) => {
254
- const file = pathToFileURL(filePath).toString();
255
- if (file.indexOf(`/commands/`) > -1 &&
256
- file.indexOf(`/assets/`) < 0 &&
257
- file.endsWith('.js') &&
258
- !file.endsWith('.spec.js')) {
259
- try {
260
- const command = await import(file);
261
- if (command.default instanceof Command) {
262
- this.loadCommand(command.default);
263
- }
264
- }
265
- catch (e) {
266
- this.closeWithError(e, { options: {} });
267
- }
268
- }
269
- }));
279
+ loadAllCommandsInfo(loadFull = false) {
280
+ const commandsInfoFileName = loadFull ? 'allCommandsFull.json' : 'allCommands.json';
281
+ this.commands = require(path.join(__dirname, '..', '..', commandsInfoFileName));
270
282
  }
271
283
  /**
272
284
  * Loads command files into CLI based on the specified arguments.
273
285
  *
274
286
  * @param commandNameWords Array of words specified as args
275
- */
287
+ */
276
288
  async loadCommandFromArgs(commandNameWords) {
277
- this.currentCommandName = commandNameWords.join(' ');
278
289
  if (commandNameWords.length === 0) {
279
- await this.loadAllCommands();
280
290
  return;
281
291
  }
282
- const isCompletionCommand = commandNameWords.indexOf('completion') > -1;
283
- if (isCompletionCommand) {
284
- await this.loadAllCommands();
285
- return;
286
- }
287
- let commandFilePath = '';
288
- if (commandNameWords.length === 1) {
289
- commandFilePath = path.join(this.commandsFolder, 'commands', `${commandNameWords[0]}.js`);
290
- }
291
- else {
292
- if (commandNameWords.length === 2) {
293
- commandFilePath = path.join(this.commandsFolder, commandNameWords[0], 'commands', `${commandNameWords.join('-')}.js`);
294
- }
295
- else {
296
- commandFilePath = path.join(this.commandsFolder, commandNameWords[0], 'commands', commandNameWords[1], commandNameWords.slice(1).join('-') + '.js');
297
- }
292
+ this.currentCommandName = commandNameWords.join(' ');
293
+ const commandFilePath = this.commands
294
+ .find(c => c.name === this.currentCommandName ||
295
+ c.aliases?.find(a => a === this.currentCommandName))?.file ?? '';
296
+ if (commandFilePath) {
297
+ await this.loadCommandFromFile(commandFilePath);
298
298
  }
299
- await this.loadCommandFromFile(commandFilePath);
300
299
  }
301
300
  async loadOptionsFromContext(commandOptions, debug) {
302
301
  const filePath = '.m365rc.json';
@@ -339,39 +338,37 @@ export class Cli {
339
338
  * Loads command from the specified file into CLI. If can't find the file
340
339
  * or the file doesn't contain a command, loads all available commands.
341
340
  *
342
- * @param commandFilePath File path of the file with command to load
341
+ * @param commandFilePathUrl File path of the file with command to load
343
342
  */
344
- async loadCommandFromFile(commandFilePath) {
345
- if (!fs.existsSync(commandFilePath)) {
346
- await this.loadAllCommands();
343
+ async loadCommandFromFile(commandFileUrl) {
344
+ const commandsFolder = path.join(__dirname, '../m365');
345
+ const filePath = path.join(commandsFolder, commandFileUrl);
346
+ if (!fs.existsSync(filePath)) {
347
+ // reset command name
348
+ this.currentCommandName = undefined;
347
349
  return;
348
350
  }
349
351
  try {
350
- const commandFileUrl = pathToFileURL(commandFilePath).toString();
351
- const command = await import(commandFileUrl);
352
+ const command = await import(pathToFileURL(filePath).toString());
352
353
  if (command.default instanceof Command) {
353
- this.loadCommand(command.default);
354
+ const commandInfo = this.commands.find(c => c.file === commandFileUrl);
355
+ this.commandToExecute = Cli.getCommandInfo(command.default, commandFileUrl, commandInfo?.help);
354
356
  }
355
- else {
356
- await this.loadAllCommands();
357
- }
358
- }
359
- catch {
360
- await this.loadAllCommands();
361
357
  }
358
+ catch { }
362
359
  }
363
- static getCommandInfo(command) {
360
+ static getCommandInfo(command, filePath = '', helpFilePath = '') {
364
361
  return {
365
362
  aliases: command.alias(),
366
363
  name: command.name,
364
+ description: command.description,
367
365
  command: command,
368
366
  options: this.getCommandOptions(command),
369
- defaultProperties: command.defaultProperties()
367
+ defaultProperties: command.defaultProperties(),
368
+ file: filePath,
369
+ help: helpFilePath
370
370
  };
371
371
  }
372
- loadCommand(command) {
373
- this.commands.push(Cli.getCommandInfo(command));
374
- }
375
372
  static getCommandOptions(command) {
376
373
  const options = [];
377
374
  command.options.forEach(option => {
@@ -508,7 +505,7 @@ export class Cli {
508
505
  if (arrayType !== 'object') {
509
506
  return logStatement.join(os.EOL);
510
507
  }
511
- // if output type has been set to 'text' or 'csv', process the retrieved
508
+ // if output type has been set to 'text', process the retrieved
512
509
  // data so that returned objects contain only default properties specified
513
510
  // on the current command. If there is no current command or the
514
511
  // command doesn't specify default properties, return original data
@@ -568,58 +565,39 @@ export class Cli {
568
565
  process.exit(exitCode);
569
566
  }
570
567
  printCommandHelp(helpMode) {
571
- let helpFilePath = '';
572
- let commandNameWords = [];
573
- if (this.commandToExecute) {
574
- commandNameWords = (this.commandToExecute.name).split(' ');
575
- }
576
- const pathChunks = [this.commandsFolder, '..', '..', 'docs', 'docs', 'cmd'];
577
- if (commandNameWords.length === 1) {
578
- pathChunks.push(`${commandNameWords[0]}.mdx`);
579
- }
580
- else {
581
- if (commandNameWords.length === 2) {
582
- pathChunks.push(commandNameWords[0], `${commandNameWords.join('-')}.mdx`);
583
- }
584
- else {
585
- pathChunks.push(commandNameWords[0], commandNameWords[1], commandNameWords.slice(1).join('-') + '.mdx');
586
- }
587
- }
588
- helpFilePath = path.join(...pathChunks);
568
+ const docsRootDir = path.join(__dirname, '..', '..', 'docs');
569
+ const helpFilePath = path.join(docsRootDir, 'docs', 'cmd', this.commandToExecute.help);
589
570
  if (fs.existsSync(helpFilePath)) {
590
571
  let helpContents = fs.readFileSync(helpFilePath, 'utf8');
591
572
  helpContents = this.getHelpSection(helpMode, helpContents);
592
- helpContents = md.md2plain(helpContents, path.join(this.commandsFolder, '..', '..', 'docs'));
573
+ helpContents = md.md2plain(helpContents, docsRootDir);
593
574
  Cli.log();
594
575
  Cli.log(helpContents);
595
576
  }
596
577
  }
597
578
  async getHelpMode(options) {
598
- const h = options.h;
599
- const help = options.help;
579
+ const { h, help } = options;
580
+ if (!h && !help) {
581
+ return this.getSettingWithDefaultValue(settingsNames.helpMode, Cli.defaultHelpMode);
582
+ }
600
583
  // user passed -h or --help, let's see if they passed a specific mode
601
584
  // or requested the default
602
- if (h || help) {
603
- const helpMode = h ?? help;
604
- if (typeof helpMode === 'boolean' || typeof helpMode !== 'string') {
605
- // requested default mode or passed a number, let's use default
606
- return this.getSettingWithDefaultValue(settingsNames.helpMode, Cli.defaultHelpMode);
585
+ const helpMode = h ?? help;
586
+ if (typeof helpMode === 'boolean' || typeof helpMode !== 'string') {
587
+ // requested default mode or passed a number, let's use default
588
+ return this.getSettingWithDefaultValue(settingsNames.helpMode, Cli.defaultHelpMode);
589
+ }
590
+ else {
591
+ const lowerCaseHelpMode = helpMode.toLowerCase();
592
+ if (Cli.helpModes.indexOf(lowerCaseHelpMode) < 0) {
593
+ await Cli.getInstance().closeWithError(`Unknown help mode ${helpMode}. Allowed values are ${Cli.helpModes.join(', ')}`, { options }, false);
594
+ /* c8 ignore next 2 */
595
+ return ''; // noop
607
596
  }
608
597
  else {
609
- const lowerCaseHelpMode = helpMode.toLowerCase();
610
- if (Cli.helpModes.indexOf(lowerCaseHelpMode) < 0) {
611
- await Cli.getInstance().closeWithError(`Unknown help mode ${helpMode}. Allowed values are ${Cli.helpModes.join(', ')}`, { options }, false);
612
- /* c8 ignore next 2 */
613
- return ''; // noop
614
- }
615
- else {
616
- return lowerCaseHelpMode;
617
- }
598
+ return lowerCaseHelpMode;
618
599
  }
619
600
  }
620
- else {
621
- return this.getSettingWithDefaultValue(settingsNames.helpMode, Cli.defaultHelpMode);
622
- }
623
601
  }
624
602
  getHelpSection(helpMode, helpContents) {
625
603
  if (helpMode === 'full') {
@@ -709,7 +687,7 @@ export class Cli {
709
687
  Cli.log();
710
688
  const sortedCommandNamesToPrint = Object.getOwnPropertyNames(commandsToPrint).sort();
711
689
  sortedCommandNamesToPrint.forEach(commandName => {
712
- Cli.log(` ${`${commandName} [options]`.padEnd(maxLength, ' ')} ${commandsToPrint[commandName].command.description}`);
690
+ Cli.log(` ${`${commandName} [options]`.padEnd(maxLength, ' ')} ${commandsToPrint[commandName].description}`);
713
691
  });
714
692
  }
715
693
  const namesOfCommandGroupsToPrint = Object.keys(commandGroupsToPrint);
@@ -0,0 +1,9 @@
1
+ export const timings = {
2
+ api: [],
3
+ core: [],
4
+ command: [],
5
+ options: [],
6
+ total: [],
7
+ validation: []
8
+ };
9
+ //# sourceMappingURL=timings.js.map
package/dist/index.js CHANGED
@@ -1,11 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import fs from 'fs';
3
- import path from 'path';
4
- import url from 'url';
5
2
  import { Cli } from './cli/Cli.js';
6
3
  import { telemetry } from './telemetry.js';
7
4
  import { app } from './utils/app.js';
8
- const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
9
5
  // required to make console.log() in combination with piped output synchronous
10
6
  // on Windows/in PowerShell so that the output is not trimmed by calling
11
7
  // process.exit() after executing the command, while the output is still
@@ -18,14 +14,12 @@ if (!process.env.CLIMICROSOFT365_NOUPDATE) {
18
14
  updateNotifier.default({ pkg: app.packageJson() }).notify({ defer: false });
19
15
  });
20
16
  }
21
- fs.realpath(__dirname, async (err, resolvedPath) => {
22
- try {
23
- const cli = Cli.getInstance();
24
- await cli.execute(path.join(resolvedPath, 'm365'), process.argv.slice(2));
25
- }
26
- catch (e) {
27
- telemetry.trackException(e);
28
- process.exit(1);
29
- }
30
- });
17
+ try {
18
+ const cli = Cli.getInstance();
19
+ cli.execute(process.argv.slice(2));
20
+ }
21
+ catch (e) {
22
+ telemetry.trackException(e);
23
+ process.exit(1);
24
+ }
31
25
  //# sourceMappingURL=index.js.map
@@ -70,10 +70,23 @@ _a = CliConfigSetCommand, _CliConfigSetCommand_instances = new WeakSet(), _CliCo
70
70
  allowedErrorOutputs.indexOf(args.options.value) === -1) {
71
71
  return `${args.options.value} is not a valid value for the option ${args.options.key}. Allowed values: ${allowedErrorOutputs.join(', ')}`;
72
72
  }
73
+ if (args.options.key === settingsNames.promptListPageSize &&
74
+ typeof args.options.value !== 'number') {
75
+ return `${args.options.value} is not a valid value for the option ${args.options.key}. The value has to be a number.`;
76
+ }
77
+ if (args.options.key === settingsNames.promptListPageSize &&
78
+ args.options.value <= 0) {
79
+ return `${args.options.value} is not a valid value for the option ${args.options.key}. The number has to be higher than 0.`;
80
+ }
73
81
  if (args.options.key === settingsNames.helpMode &&
74
82
  Cli.helpModes.indexOf(args.options.value) === -1) {
75
83
  return `${args.options.value} is not a valid value for the option ${args.options.key}. Allowed values: ${Cli.helpModes.join(', ')}`;
76
84
  }
85
+ const allowedAuthTypes = ['certificate', 'deviceCode', 'password', 'identity', 'browser', 'secret'];
86
+ if (args.options.key === settingsNames.authType &&
87
+ allowedAuthTypes.indexOf(args.options.value) === -1) {
88
+ return `${args.options.value} is not a valid value for the option ${args.options.key}. Allowed values: ${allowedAuthTypes.join(', ')}`;
89
+ }
77
90
  return true;
78
91
  });
79
92
  };
@@ -11,6 +11,8 @@ import config from '../../config.js';
11
11
  import { accessToken } from '../../utils/accessToken.js';
12
12
  import { misc } from '../../utils/misc.js';
13
13
  import commands from './commands.js';
14
+ import { settingsNames } from '../../settingsNames.js';
15
+ import { Cli } from '../../cli/Cli.js';
14
16
  class LoginCommand extends Command {
15
17
  get name() {
16
18
  return commands.LOGIN;
@@ -35,9 +37,10 @@ class LoginCommand extends Command {
35
37
  if (this.verbose) {
36
38
  await logger.logToStderr(`Signing in to Microsoft 365...`);
37
39
  }
40
+ const authType = args.options.authType || Cli.getInstance().getSettingWithDefaultValue(settingsNames.authType, 'deviceCode');
38
41
  auth.service.appId = args.options.appId || config.cliAadAppId;
39
42
  auth.service.tenant = args.options.tenant || config.tenant;
40
- switch (args.options.authType) {
43
+ switch (authType) {
41
44
  case 'password':
42
45
  auth.service.authType = AuthType.Password;
43
46
  auth.service.userName = args.options.userName;
@@ -126,7 +129,7 @@ class LoginCommand extends Command {
126
129
  _a = LoginCommand, _LoginCommand_instances = new WeakSet(), _LoginCommand_initTelemetry = function _LoginCommand_initTelemetry() {
127
130
  this.telemetry.push((args) => {
128
131
  Object.assign(this.telemetryProperties, {
129
- authType: args.options.authType || 'deviceCode',
132
+ authType: args.options.authType || Cli.getInstance().getSettingWithDefaultValue(settingsNames.authType, 'deviceCode'),
130
133
  cloud: args.options.cloud ?? CloudType.Public
131
134
  });
132
135
  });
@@ -156,7 +159,8 @@ _a = LoginCommand, _LoginCommand_instances = new WeakSet(), _LoginCommand_initTe
156
159
  });
157
160
  }, _LoginCommand_initValidators = function _LoginCommand_initValidators() {
158
161
  this.validators.push(async (args) => {
159
- if (args.options.authType === 'password') {
162
+ const authType = args.options.authType || Cli.getInstance().getSettingWithDefaultValue(settingsNames.authType, 'deviceCode');
163
+ if (authType === 'password') {
160
164
  if (!args.options.userName) {
161
165
  return 'Required option userName missing';
162
166
  }
@@ -164,7 +168,7 @@ _a = LoginCommand, _LoginCommand_instances = new WeakSet(), _LoginCommand_initTe
164
168
  return 'Required option password missing';
165
169
  }
166
170
  }
167
- if (args.options.authType === 'certificate') {
171
+ if (authType === 'certificate') {
168
172
  if (args.options.certificateFile && args.options.certificateBase64Encoded) {
169
173
  return 'Specify either certificateFile or certificateBase64Encoded, but not both.';
170
174
  }
@@ -177,11 +181,11 @@ _a = LoginCommand, _LoginCommand_instances = new WeakSet(), _LoginCommand_initTe
177
181
  }
178
182
  }
179
183
  }
180
- if (args.options.authType &&
181
- _a.allowedAuthTypes.indexOf(args.options.authType) < 0) {
182
- return `'${args.options.authType}' is not a valid authentication type. Allowed authentication types are ${_a.allowedAuthTypes.join(', ')}`;
184
+ if (authType &&
185
+ _a.allowedAuthTypes.indexOf(authType) < 0) {
186
+ return `'${authType}' is not a valid authentication type. Allowed authentication types are ${_a.allowedAuthTypes.join(', ')}`;
183
187
  }
184
- if (args.options.authType === 'secret') {
188
+ if (authType === 'secret') {
185
189
  if (!args.options.secret) {
186
190
  return 'Required option secret missing';
187
191
  }
@@ -17,10 +17,12 @@ class FlowEnvironmentListCommand extends AzmgmtCommand {
17
17
  }
18
18
  try {
19
19
  const res = await odata.getAllItems(`${this.resource}providers/Microsoft.ProcessSimple/environments?api-version=2016-11-01`);
20
- if (args.options.output !== 'json' && res.length > 0) {
21
- res.forEach(e => {
22
- e.displayName = e.properties.displayName;
23
- });
20
+ if (res.length > 0) {
21
+ if (args.options.output !== 'json') {
22
+ res.forEach(e => {
23
+ e.displayName = e.properties.displayName;
24
+ });
25
+ }
24
26
  await logger.log(res);
25
27
  }
26
28
  }
@@ -16,10 +16,10 @@ export const workflow = {
16
16
  uses: "actions/checkout@v3.5.3"
17
17
  },
18
18
  {
19
- name: "Use Node.js 16.x",
19
+ name: "Use Node.js",
20
20
  uses: "actions/setup-node@v3.7.0",
21
21
  with: {
22
- "node-version": "16.x"
22
+ "node-version": "18.x"
23
23
  }
24
24
  },
25
25
  {
@@ -32,7 +32,7 @@ export const workflow = {
32
32
  },
33
33
  {
34
34
  name: "CLI for Microsoft 365 Login",
35
- uses: "pnp/action-cli-login@v2.2.2",
35
+ uses: "pnp/action-cli-login@v2.2.4",
36
36
  with: {
37
37
  "CERTIFICATE_ENCODED": "${{ secrets.CERTIFICATE_ENCODED }}",
38
38
  "CERTIFICATE_PASSWORD": "${{ secrets.CERTIFICATE_PASSWORD }}",
@@ -41,7 +41,7 @@ export const workflow = {
41
41
  },
42
42
  {
43
43
  name: "CLI for Microsoft 365 Deploy App",
44
- uses: "pnp/action-cli-deploy@v3.0.1",
44
+ uses: "pnp/action-cli-deploy@v4.0.0",
45
45
  with: {
46
46
  "APP_FILE_PATH": "sharepoint/solution/{{ solutionName }}.sppkg",
47
47
  "SKIP_FEATURE_DEPLOYMENT": false,
@@ -18,4 +18,4 @@ export default [
18
18
  new FN002016_DEVDEP_types_react_dom('17'),
19
19
  new FN002019_DEVDEP_microsoft_rush_stack_compiler(['4.7'])
20
20
  ];
21
- //# sourceMappingURL=doctor-1.18.1-rc.0.js.map
21
+ //# sourceMappingURL=doctor-1.18.1.js.map