@forge/cli-shared 9.10.0-next.1-experimental-1e95696 → 9.10.0-next.11

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/out/ui/text.js CHANGED
@@ -29,11 +29,15 @@ const go = (link) => buildTerminalLink(`https://go.atlassian.com/${link}`);
29
29
  const gettingStartedDACLink = go('dac/platform/forge/getting-started/#log-in-with-an-atlassian-api-token');
30
30
  const command = (...args) => chalk_1.default.bold(args.join(' '));
31
31
  const forge = (...args) => command('forge', ...args);
32
+ const autoSpaceSentences = (...sentences) => sentences
33
+ .filter((sentence) => sentence.length > 0)
34
+ .join(' ');
32
35
  function itemList(items, indent) {
33
36
  return items.map((item) => `${indent ?? ' '}- ${item}`).join(`\n${indent ?? ''}`);
34
37
  }
35
38
  const fatalError = (message) => chalk_1.default.bold(chalk_1.default.red(message));
36
39
  const approveRuleDescription = 'list of validation rules to approve';
40
+ const keytarAccessErrorBase = (message) => `Keytar error detected: ${message}`;
37
41
  const capitalise = (word) => word.charAt(0).toUpperCase() + word.slice(1);
38
42
  exports.capitalise = capitalise;
39
43
  const getLintMessage = (line, column, message, level, colourFunction, reference) => `${chalk_1.default.dim(`${line}:${column}`.padEnd(7))} ${colourFunction(level.padEnd(8))} ${message} ${chalk_1.default.dim(reference)}\n`;
@@ -45,6 +49,16 @@ const checkLintTotalPlurals = (numErrors, numWarnings, numApprovals, numFixableE
45
49
  pluralCheckedFixableErrors: `${numFixableErrors} ${numFixableErrors === 1 ? 'error' : 'errors'}`,
46
50
  pluralCheckedFixableWarnings: `${numFixableWarnings} ${numFixableWarnings === 1 ? 'warning' : 'warnings'}`
47
51
  });
52
+ const platformKeytarRecommendations = () => {
53
+ switch (process.platform) {
54
+ case 'darwin':
55
+ return 'Ensure you enable access to the macOS keychain when prompted.';
56
+ case 'linux':
57
+ return `Ensure you have ${chalk_1.default.bold('libsecret')} installed.`;
58
+ default:
59
+ return '';
60
+ }
61
+ };
48
62
  const globalTargetLocation = ({ unit, org }) => unit && org
49
63
  ? `in unit ${chalk_1.default.bold(unit)} in organization ${chalk_1.default.bold(org)}`
50
64
  : unit
@@ -54,9 +68,15 @@ exports.Text = {
54
68
  buildTerminalLink,
55
69
  go,
56
70
  error: {
57
- noTokenStored: `Not logged in. Run ${forge('login')}, or set the FORGE_EMAIL and FORGE_API_TOKEN environment variables before trying again. See ${gettingStartedDACLink} for more.`,
58
- credentialsFilePermissions: `The CLI couldn't securely store your login credentials in the local credentials file. ` +
59
- `Set the FORGE_EMAIL and FORGE_API_TOKEN environment variables instead. See ${gettingStartedDACLink} for more.`,
71
+ noKeytar: autoSpaceSentences(`The CLI couldn't securely store your login credentials in a local keychain.`, platformKeytarRecommendations(), `If a local keychain is not available, use environment variables before trying again. See ${gettingStartedDACLink} for more.`),
72
+ noTokenStored: `Not logged in. If a local keychain is available, run ${forge('login')}, otherwise set environment variables before trying again. See ${gettingStartedDACLink} for more.`,
73
+ keytarAccessError: {
74
+ other: (message) => keytarAccessErrorBase(message),
75
+ mac: (message) => keytarAccessErrorBase(message) +
76
+ `\nSomething went wrong while accessing Keychain Access. Try locking and unlocking the login keychain.`,
77
+ linux: (message) => keytarAccessErrorBase(message) + `\nSomething went wrong while accessing Secret Service API.`,
78
+ windows: (message) => keytarAccessErrorBase(message) + `\nSomething went wrong while accessing Credentials Vault.`
79
+ },
60
80
  outdatedCLIVersion: (installed, latest) => `Warning: Your version of Forge CLI is out of date. We recommend you update to the latest version to get the latest features and bug fixes.` +
61
81
  `\nRun ${command('npm', 'install', '-g', `${cli_details_1.FORGE_CLI_PACKAGE}@latest`)} to update from version ${chalk_1.default.bold(installed)} to ${chalk_1.default.bold(latest)}.` +
62
82
  `\n`,
@@ -69,7 +89,7 @@ exports.Text = {
69
89
  invalidSite: 'The site you entered is not an Atlassian site. Rerun the command with the URL to an Atlassian site to install the app.',
70
90
  invalidWorkspace: 'The workspace you entered is not a valid workspace. Rerun the command with the URL to a valid workspace to install the app.',
71
91
  invalidInstallationContext: 'Could not find an installation for the provided Atlassian app',
72
- invalidTokenInCredentialFile: `Your API token is no longer valid. Run ${forge('login')} to reset your login credentials.`,
92
+ invalidTokenInKeytar: `Your API token is no longer valid. Run ${forge('login')} to reset your login credentials.`,
73
93
  invalidUpgradeTarget: 'You must specify either "all" or "code" as the upgrade target.',
74
94
  invalidTokenInEnv: (instructionsUrl, emailVar, tokenVar) => `The API token on your machine is no longer valid.` +
75
95
  `\n 1) Get a new API token: ${instructionsUrl}` +
@@ -102,6 +122,9 @@ exports.Text = {
102
122
  environmentIsNotDefined: (envKey) => `Environment with name ${envKey} not defined. Create this environment with ${chalk_1.default.bold(`forge environments create -e ${envKey}`)} before proceeding.`
103
123
  },
104
124
  warning: {
125
+ plaintextCredentialsFound: (url) => `Your credentials were stored in plaintext by a previous version of the Forge CLI. For additional security, revoke your existing API token by visting this URL ${buildTerminalLink(url)}.`,
126
+ plaintextCredentialsMigrated: 'The credentials found in plaintext have been migrated to your local keychain.',
127
+ plaintextCredentialsNotMigrated: autoSpaceSentences(`The CLI couldn't securely store your login credentials in a local keychain.`, platformKeytarRecommendations(), `If a local keychain is not available, use environment variables instead. See ${gettingStartedDACLink} for more information.`),
105
128
  unsupportedNodeVersion: (_userNodeVersion, supportedNodeVersions) => log_color_1.LogColor.warn(`Warning: Forge CLI supports Node.js ${supportedNodeVersions}.` +
106
129
  `\nUnsupported Node.js versions are not guaranteed to work correctly.\n`),
107
130
  deprecation: {
@@ -218,7 +241,7 @@ exports.Text = {
218
241
  },
219
242
  error: {
220
243
  personalCredentialsEnv: (emailKey, apiTokenKey) => `We couldn't get your Atlassian account information. Check the ${emailKey} and ${apiTokenKey} environment variables.`,
221
- personalCredentialsFile: `We couldn't get your Atlassian account information. You may need to run ${forge('login')} to log in again.`
244
+ personalCredentialsKeytar: `We couldn't get your Atlassian account information. You may need to run ${forge('login')} to log in again.`
222
245
  }
223
246
  },
224
247
  feedback: {
@@ -254,8 +277,8 @@ What do you like or don't like about Forge? Share your feedback below or press C
254
277
  introWithCurrentDirectory: (currentDirectory) => `Creating an app in your current directory:\n\n ${chalk_1.default.bold(currentDirectory)}\n`,
255
278
  optionTemplate: 'specify the template to use',
256
279
  optionDirectory: 'specify the directory to create (uses the template name by default)',
257
- optionSpace: 'specify the Developer Space id to use',
258
- optionAcceptTerms: 'automatically accept terms and conditions in non-interactive mode',
280
+ optionSpace: `specify the Developer Space id to use (see your Developer Spaces by running ${forge('developer-spaces', 'list')})`,
281
+ optionAcceptTerms: 'accept terms and conditions without prompting',
259
282
  optionPersonal: 'register as a personal app',
260
283
  overviewAppName: `\nName your app. The app name can include dashes, spaces, and underscores.\n`,
261
284
  overviewTemplates: '\nStart with a template. Each template contains the required files to be a valid app.\n',
@@ -272,6 +295,7 @@ What do you like or don't like about Forge? Share your feedback below or press C
272
295
  taskRegister: 'Registering app',
273
296
  taskCreateEnvironments: 'Creating environments',
274
297
  taskPackages: 'Installing dependencies',
298
+ taskModules: 'Adding modules',
275
299
  error: {
276
300
  dirtyDirectory: 'Destination directory is not empty',
277
301
  app: {
@@ -283,12 +307,40 @@ What do you like or don't like about Forge? Share your feedback below or press C
283
307
  name: {
284
308
  tooLong: (max) => `The app name exceeds ${max} characters. Run ${forge('create')} using a shorter app name.`
285
309
  },
310
+ nonInteractive: {
311
+ missingInputs: (missingInputs, nextCommand) => {
312
+ const labelWidth = Math.max(...missingInputs.map(({ label }) => label.length));
313
+ const inputs = missingInputs.map(({ label, hint }) => `${label.padEnd(labelWidth)} ${hint}`);
314
+ return `Missing required inputs for non-interactive mode.\n\nProvide:\n${itemList(inputs)}\n\nNext: ${forge('create', ...nextCommand)}`;
315
+ },
316
+ labels: {
317
+ appName: '<app name>',
318
+ template: '-t, --template <template name>',
319
+ developerSpace: '-s, --developer-space-id <Developer Space id>',
320
+ acceptTerms: '-y, --accept-terms'
321
+ },
322
+ placeholders: {
323
+ appName: '<app name>',
324
+ template: '<template name>',
325
+ directory: '<directory name>',
326
+ developerSpace: '<Developer Space id>'
327
+ },
328
+ appNameHint: (maxLength) => `up to ${maxLength} characters`,
329
+ templateHint: 'for example: blank',
330
+ developerSpaceHint: `find one with: ${forge('developer-spaces', 'list', '--json')}`,
331
+ acceptTermsHint: 'accepts the Developer Terms, Privacy Policy and usage pricing'
332
+ },
286
333
  template: {
287
334
  download: (template) => `Failed to download the ${template} template. Run ${forge('create')} again.`,
288
335
  notFound: (template) => `The template ${template} doesn't exist. Run ${forge('create')} using a different template.`,
289
336
  noTemplates: 'There are no templates to choose from.',
290
337
  unexpectedArchiveFormat: 'Unexpected template format.'
291
338
  },
339
+ preset: {
340
+ notFound: (preset) => `The preset ${preset} doesn't exist. Run ${forge('create')} using a different preset.`,
341
+ withTemplate: `Run ${forge('create')} with either --template or --preset, not both.`,
342
+ modulesFailed: `Your app was created, but some preset modules couldn't be added. Run ${forge('module add')} from the app directory to add them.`
343
+ },
292
344
  packages: {
293
345
  installFail: `Something went wrong while installing app dependencies. Try running ${forge('create')} again.`
294
346
  }
@@ -442,6 +494,7 @@ What do you like or don't like about Forge? Share your feedback below or press C
442
494
  defaultEnv: {
443
495
  info: 'You do not have a default development environment set. This is required to run commands without specifying an environment. Make sure not to use sensitive information when naming your default development environment.',
444
496
  prompt: 'Enter a name for your default development environment:',
497
+ notSetNonInteractive: `No environment was given and you don't have a default development environment. Pass --environment, or set a default with ${forge('settings', 'set', 'default-environment', '<environment>')}.`,
445
498
  warn: `${chalk_1.default.bold('Warning:')} A development environment with this name already exists. If you continue, you may be using the same environment as another contributor.`,
446
499
  confirm: 'Do you want to continue?',
447
500
  setSuccess: (envKey, envType) => `${exports.Text.env.displayEnvironment(envKey, envType)} has been set as your default development environment`,
@@ -1297,6 +1350,51 @@ ${buildTerminalLink(link)}\n`,
1297
1350
  banner: `Showing latest deployments of your app:`,
1298
1351
  noDeployments: `No deployments found for this app.\nRun ${forge('deploy')} to deploy your app to an environment.`
1299
1352
  },
1353
+ deployStatus: {
1354
+ cmd: 'show the placement deployment status of an app version in an environment',
1355
+ majorVersionOption: 'specify the major version to show (defaults to the latest deployed version)',
1356
+ banner: (envKey, envType, version) => `${log_symbols_1.default.info} Environment: ${exports.Text.env.displayEnvironment(envKey, envType)} (Version: ${version})`,
1357
+ artifactUploaded: (createdAt, buildTag) => {
1358
+ const buildTagText = buildTag ? ` from build with tag ${buildTag}` : '';
1359
+ return `${log_symbols_1.default.success} App artifact uploaded${buildTagText} at ${createdAt}`;
1360
+ },
1361
+ overall: {
1362
+ succeeded: (succeeded, total) => `${log_symbols_1.default.success} Deployment succeeded (${succeeded}/${total} placements)`,
1363
+ failed: (succeeded, total) => `${log_symbols_1.default.error} Deployment failed (${succeeded}/${total} placements succeeded)`,
1364
+ inProgress: (succeeded, total, inProgress) => `${log_symbols_1.default.info} Deployment still in progress (${succeeded}/${total} placements succeeded, ${inProgress} in progress)`
1365
+ },
1366
+ checkAgain: (envKey, majorVersion) => `Run ${forge('deploy status', '-e', (0, environment_1.environmentToOption)(envKey), ...(majorVersion ? ['-v', String(majorVersion)] : []))} again to check for updates.`,
1367
+ table: {
1368
+ placementType: 'Placement type',
1369
+ placement: 'Placement',
1370
+ status: 'Status',
1371
+ failedStep: 'Failed step',
1372
+ lastUpdated: 'Last updated'
1373
+ },
1374
+ placementTypeLabel: (placementType) => ({
1375
+ [graphql_runtime_enums_1.AppPlacementType.Region]: 'Region',
1376
+ [graphql_runtime_enums_1.AppPlacementType.CustomerDataPlane]: 'Customer data plane',
1377
+ [graphql_runtime_enums_1.AppPlacementType.IsolationContext]: 'Isolation context'
1378
+ })[placementType] ?? placementType,
1379
+ groupLabel: (placementTypeLabel, succeeded, total) => `${placementTypeLabel} (${succeeded}/${total})`,
1380
+ statusLabel: (status) => ({
1381
+ [graphql_runtime_enums_1.AppVersionDeploymentStatus.Succeeded]: chalk_1.default.green('Succeeded'),
1382
+ [graphql_runtime_enums_1.AppVersionDeploymentStatus.Failed]: chalk_1.default.red('Failed'),
1383
+ [graphql_runtime_enums_1.AppVersionDeploymentStatus.InProgress]: chalk_1.default.yellow('In progress')
1384
+ })[status] ?? status,
1385
+ stepLabel: (step) => ({
1386
+ [graphql_runtime_enums_1.AppVersionDeploymentStep.Artifact]: 'Artifact',
1387
+ [graphql_runtime_enums_1.AppVersionDeploymentStep.Function]: 'Function',
1388
+ [graphql_runtime_enums_1.AppVersionDeploymentStep.Containers]: 'Containers',
1389
+ [graphql_runtime_enums_1.AppVersionDeploymentStep.HostedResources]: 'Hosted resources',
1390
+ [graphql_runtime_enums_1.AppVersionDeploymentStep.CustomScopes]: 'Custom scopes',
1391
+ [graphql_runtime_enums_1.AppVersionDeploymentStep.OauthClient]: 'OAuth client',
1392
+ [graphql_runtime_enums_1.AppVersionDeploymentStep.ScheduledTriggers]: 'Scheduled triggers'
1393
+ })[step] ?? step,
1394
+ noPlacements: `No placements found for this version. Placements are added when your app is installed.\nRun ${forge('install')} to install your app.`,
1395
+ noVersion: (envKey, envType) => `No deployed version found in the ${exports.Text.env.displayEnvironment(envKey, envType)} environment. Run ${forge('deploy')} to deploy your app first.`,
1396
+ noStatus: (version, envKey, envType) => `No deployment status is available for version ${version} in the ${exports.Text.env.displayEnvironment(envKey, envType)} environment yet.`
1397
+ },
1300
1398
  tunnel: {
1301
1399
  cmd: 'start a tunnel to connect your local code with the app running in the development environment',
1302
1400
  optionDebugger: 'enable debugger mode',
@@ -1696,6 +1794,10 @@ ${buildTerminalLink(link)}\n`,
1696
1794
  description: 'Change your default development environment',
1697
1795
  info: `To view all environments for this app, run ${forge('environments', 'list')}.`
1698
1796
  },
1797
+ nonInteractive: {
1798
+ description: 'Run commands without prompts: auto (when an agent runs the command, not in CI), on, or off. FORGE_NON_INTERACTIVE overrides it',
1799
+ invalidValue: 'Invalid value specified. Valid values: auto, on, off'
1800
+ },
1699
1801
  customEffects: {
1700
1802
  description: 'Enable custom spinner effects',
1701
1803
  setupError: chalk_1.default.yellow('Failed to fetch custom spinner config. Custom spinner effects can be disabled via forge settings')
@@ -1769,7 +1871,10 @@ When errors occur during Forge command execution, error details will be sent to
1769
1871
  description: 'run the command without input prompts',
1770
1872
  error: {
1771
1873
  missingRequiredOption: (command, requiredOptions) => `${command} --non-interactive requires ${requiredOptions.join(' ')}`,
1772
- missingAnalyticsPreferences: `--non-interactive requires an analytics setting. Use ${forge('settings', 'set', 'usage-analytics', '<value>')}.`
1874
+ missingAnalyticsPreferences: `--non-interactive requires an analytics setting. Use ${forge('settings', 'set', 'usage-analytics', '<value>')}.`,
1875
+ promptReached: (question) => `${question ? `"${question.trim()}" needs an answer, but` : 'This command needs input, but'} the CLI is ` +
1876
+ `running in non-interactive mode, so it can't ask. Pass the answer as an option. Run the command with ` +
1877
+ `--help to see its options.`
1773
1878
  }
1774
1879
  },
1775
1880
  customScopes: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forge/cli-shared",
3
- "version": "9.10.0-next.1-experimental-1e95696",
3
+ "version": "9.10.0-next.11",
4
4
  "description": "Common functionality for Forge CLI",
5
5
  "author": "Atlassian",
6
6
  "license": "SEE LICENSE IN LICENSE.txt",
@@ -13,8 +13,8 @@
13
13
  "prebuild": "yarn generate-graphql-types"
14
14
  },
15
15
  "dependencies": {
16
- "@forge/manifest": "13.8.1-next.0-experimental-1e95696",
17
- "@forge/util": "3.1.0-next.0-experimental-1e95696",
16
+ "@forge/manifest": "13.9.0-next.5",
17
+ "@forge/util": "4.0.0-next.2",
18
18
  "@forge/i18n": "1.0.1",
19
19
  "@sentry/node": "7.106.0",
20
20
  "@vercel/detect-agent": "^1.2.5",
@@ -39,6 +39,7 @@
39
39
  "inquirer": "^8.2.6",
40
40
  "inquirer-autocomplete-prompt": "^2.0.1",
41
41
  "io-ts": "^2.2.22",
42
+ "keytar": "^7.9.0",
42
43
  "ora": "^5.4.1",
43
44
  "recursive-readdir": "^2.2.3",
44
45
  "semver": "^7.6.0",