Skip to content

Commit 5a6ab56

Browse files
authored
Add mrt save-credentials command (#286)
* Add `mrt save-credentials` command Adds a new command to save MRT credentials (username and API key) to the ~/.mobify file, replacing the manual echo/JSON workflow. Supports --credentials-file override, --cloud-origin for alternate file paths, and --yes to skip overwrite confirmation. File is written with 0o600 permissions. * chore: add changeset for mrt save-credentials * Extract shared confirm prompt utility Move the duplicated confirm() pattern to a shared prompts.ts module. Use (y/N) format matching existing CLI conventions with default-no. * Migrate all commands to shared confirm prompt utility Replace duplicated readline-based confirm functions across 10 commands with the shared confirm() from prompts.ts. The shared utility auto-appends (y/N) or (Y/n) hints and supports configurable defaults.
1 parent b7f78ca commit 5a6ab56

18 files changed

Lines changed: 460 additions & 207 deletions

File tree

.changeset/mrt-save-credentials.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@salesforce/b2c-cli': minor
3+
'@salesforce/b2c-dx-docs': patch
4+
---
5+
6+
Add `mrt save-credentials` command to save MRT API credentials to the ~/.mobify file

docs/cli/mrt.md

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Commands for managing Managed Runtime (MRT) projects, environments, and bundles
2020
| `mrt env access-control` | `list` | Manage access control headers |
2121
| `mrt bundle` | `deploy`, `list`, `history`, `download` | Manage bundles and deployments |
2222
| `mrt tail-logs` | | Tail real-time application logs |
23+
| `mrt save-credentials` | | Save MRT credentials to ~/.mobify |
2324
| `mrt user` | `profile`, `api-key`, `email-prefs` | Manage user settings |
2425

2526
## Global MRT Flags
@@ -55,15 +56,9 @@ MRT commands use API key authentication. The API key is configured in the Manage
5556

5657
Provide the API key via one of these methods:
5758

58-
1. **Command-line flag**: `--api-key your-api-key`
59-
2. **Environment variable**: `export MRT_API_KEY=your-api-key`
60-
3. **Mobify config file**: `~/.mobify` with `api_key` field
61-
62-
```json
63-
{
64-
"api_key": "your-mrt-api-key"
65-
}
66-
```
59+
1. **Save credentials** (recommended): `b2c mrt save-credentials --user you@example.com --api-key your-api-key`
60+
2. **Command-line flag**: `--api-key your-api-key`
61+
3. **Environment variable**: `export MRT_API_KEY=your-api-key`
6762

6863
For complete setup instructions, see the [Authentication Guide](/guide/authentication#managed-runtime-api-key).
6964

@@ -539,6 +534,37 @@ b2c mrt tail-logs -p my-storefront -e staging --json
539534

540535
---
541536

537+
## Save Credentials
538+
539+
### b2c mrt save-credentials
540+
541+
Save MRT credentials (username and API key) to the `~/.mobify` file. Prompts for confirmation before overwriting an existing file.
542+
543+
```bash
544+
# Save credentials
545+
b2c mrt save-credentials --user user@example.com --api-key abc123
546+
547+
# Overwrite without confirmation
548+
b2c mrt save-credentials --user user@example.com --api-key abc123 --yes
549+
550+
# Save to a custom credentials file
551+
b2c mrt save-credentials --user user@example.com --api-key abc123 --credentials-file ./my-creds
552+
553+
# Save for a specific cloud origin (writes to ~/.mobify--<hostname>)
554+
b2c mrt save-credentials --user user@example.com --api-key abc123 --cloud-origin https://cloud-staging.example.com
555+
```
556+
557+
**Flags:**
558+
| Flag | Description |
559+
|------|-------------|
560+
| `--user` | MRT username (email). Required. |
561+
| `--api-key` | MRT API key. Required. |
562+
| `--cloud-origin` | MRT cloud origin URL. Determines the credentials file path (e.g., `~/.mobify--<hostname>`). |
563+
| `--credentials-file` | Explicit path to credentials file (overrides default `~/.mobify`). |
564+
| `--yes`, `-y` | Overwrite existing credentials without confirmation. |
565+
566+
---
567+
542568
## User Commands
543569

544570
### b2c mrt user profile

docs/guide/authentication.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -374,11 +374,11 @@ MRT commands use a separate API key system.
374374
### Configuring the API Key
375375

376376
```bash
377-
# Environment variable
378-
export MRT_API_KEY=your-mrt-api-key
377+
# Save credentials to ~/.mobify
378+
b2c mrt save-credentials --user your-email@example.com --api-key your-mrt-api-key
379379

380-
# Or in ~/.mobify config file
381-
echo '{"api_key": "your-mrt-api-key"}' > ~/.mobify
380+
# Or use an environment variable
381+
export MRT_API_KEY=your-mrt-api-key
382382
```
383383

384384
## Quick Start Example

packages/b2c-cli/src/commands/code/delete.ts

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,11 @@
33
* SPDX-License-Identifier: Apache-2
44
* For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0
55
*/
6-
import * as readline from 'node:readline';
76
import {Args, Flags} from '@oclif/core';
87
import {InstanceCommand} from '@salesforce/b2c-tooling-sdk/cli';
98
import {deleteCodeVersion} from '@salesforce/b2c-tooling-sdk/operations/code';
109
import {t, withDocs} from '../../i18n/index.js';
11-
12-
/**
13-
* Simple confirmation prompt.
14-
*/
15-
async function confirm(message: string): Promise<boolean> {
16-
const rl = readline.createInterface({
17-
input: process.stdin,
18-
output: process.stderr,
19-
});
20-
21-
return new Promise((resolve) => {
22-
rl.question(`${message} `, (answer) => {
23-
rl.close();
24-
resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
25-
});
26-
});
27-
}
10+
import {confirm} from '../../prompts.js';
2811

2912
export default class CodeDelete extends InstanceCommand<typeof CodeDelete> {
3013
static hiddenAliases = ['code:delete'];
@@ -75,7 +58,7 @@ export default class CodeDelete extends InstanceCommand<typeof CodeDelete> {
7558
const confirmed = await this.operations.confirm(
7659
t(
7760
'commands.code.delete.confirm',
78-
'Are you sure you want to delete code version "{{codeVersion}}" on {{hostname}}? (y/n)',
61+
'Are you sure you want to delete code version "{{codeVersion}}" on {{hostname}}?',
7962
{codeVersion, hostname},
8063
),
8164
);

packages/b2c-cli/src/commands/mrt/env/delete.ts

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,11 @@
33
* SPDX-License-Identifier: Apache-2
44
* For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0
55
*/
6-
import * as readline from 'node:readline';
76
import {Args, Flags} from '@oclif/core';
87
import {MrtCommand} from '@salesforce/b2c-tooling-sdk/cli';
98
import {deleteEnv} from '@salesforce/b2c-tooling-sdk/operations/mrt';
109
import {t, withDocs} from '../../../i18n/index.js';
11-
12-
/**
13-
* Simple confirmation prompt.
14-
*/
15-
async function confirm(message: string): Promise<boolean> {
16-
const rl = readline.createInterface({
17-
input: process.stdin,
18-
output: process.stderr,
19-
});
20-
21-
return new Promise((resolve) => {
22-
rl.question(`${message} `, (answer) => {
23-
rl.close();
24-
resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
25-
});
26-
});
27-
}
10+
import {confirm} from '../../../prompts.js';
2811

2912
/**
3013
* Delete an environment (target) from a Managed Runtime project.
@@ -83,7 +66,7 @@ export default class MrtEnvDelete extends MrtCommand<typeof MrtEnvDelete> {
8366
const confirmed = await this.operations.confirm(
8467
t(
8568
'commands.mrt.env.delete.confirm',
86-
'Are you sure you want to delete environment "{{slug}}" from {{project}}? (y/n)',
69+
'Are you sure you want to delete environment "{{slug}}" from {{project}}?',
8770
{
8871
slug,
8972
project,

packages/b2c-cli/src/commands/mrt/env/redirect/clone.ts

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,11 @@
33
* SPDX-License-Identifier: Apache-2
44
* For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0
55
*/
6-
import * as readline from 'node:readline';
76
import {Flags} from '@oclif/core';
87
import {MrtCommand} from '@salesforce/b2c-tooling-sdk/cli';
98
import {cloneRedirects, type CloneRedirectsResult} from '@salesforce/b2c-tooling-sdk/operations/mrt';
109
import {t, withDocs} from '../../../../i18n/index.js';
11-
12-
/**
13-
* Prompt for confirmation.
14-
*/
15-
async function confirm(message: string): Promise<boolean> {
16-
const rl = readline.createInterface({
17-
input: process.stdin,
18-
output: process.stdout,
19-
});
20-
21-
return new Promise((resolve) => {
22-
rl.question(`${message} (y/N): `, (answer) => {
23-
rl.close();
24-
resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
25-
});
26-
});
27-
}
10+
import {confirm} from '../../../../prompts.js';
2811

2912
/**
3013
* Clone redirects from one environment to another.

packages/b2c-cli/src/commands/mrt/env/redirect/delete.ts

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,11 @@
33
* SPDX-License-Identifier: Apache-2
44
* For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0
55
*/
6-
import * as readline from 'node:readline';
76
import {Args, Flags} from '@oclif/core';
87
import {MrtCommand} from '@salesforce/b2c-tooling-sdk/cli';
98
import {deleteRedirect} from '@salesforce/b2c-tooling-sdk/operations/mrt';
109
import {t, withDocs} from '../../../../i18n/index.js';
11-
12-
/**
13-
* Prompt for confirmation.
14-
*/
15-
async function confirm(message: string): Promise<boolean> {
16-
const rl = readline.createInterface({
17-
input: process.stdin,
18-
output: process.stdout,
19-
});
20-
21-
return new Promise((resolve) => {
22-
rl.question(`${message} (y/N): `, (answer) => {
23-
rl.close();
24-
resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
25-
});
26-
});
27-
}
10+
import {confirm} from '../../../../prompts.js';
2811

2912
/**
3013
* Delete a redirect from an MRT environment.

packages/b2c-cli/src/commands/mrt/project/delete.ts

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,11 @@
33
* SPDX-License-Identifier: Apache-2
44
* For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0
55
*/
6-
import * as readline from 'node:readline';
76
import {Args, Flags} from '@oclif/core';
87
import {MrtCommand} from '@salesforce/b2c-tooling-sdk/cli';
98
import {deleteProject} from '@salesforce/b2c-tooling-sdk/operations/mrt';
109
import {t, withDocs} from '../../../i18n/index.js';
11-
12-
/**
13-
* Simple confirmation prompt.
14-
*/
15-
async function confirm(message: string): Promise<boolean> {
16-
const rl = readline.createInterface({
17-
input: process.stdin,
18-
output: process.stderr,
19-
});
20-
21-
return new Promise((resolve) => {
22-
rl.question(`${message} `, (answer) => {
23-
rl.close();
24-
resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
25-
});
26-
});
27-
}
10+
import {confirm} from '../../../prompts.js';
2811

2912
/**
3013
* Delete result for JSON output.
@@ -78,7 +61,7 @@ export default class MrtProjectDelete extends MrtCommand<typeof MrtProjectDelete
7861
// Confirm deletion unless --force is specified
7962
if (!force && !this.jsonEnabled()) {
8063
const confirmed = await confirm(
81-
t('commands.mrt.project.delete.confirm', 'Are you sure you want to delete project "{{slug}}"? (y/n)', {slug}),
64+
t('commands.mrt.project.delete.confirm', 'Are you sure you want to delete project "{{slug}}"?', {slug}),
8265
);
8366

8467
if (!confirmed) {

packages/b2c-cli/src/commands/mrt/project/member/remove.ts

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,11 @@
33
* SPDX-License-Identifier: Apache-2
44
* For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0
55
*/
6-
import * as readline from 'node:readline';
76
import {Args, Flags} from '@oclif/core';
87
import {MrtCommand} from '@salesforce/b2c-tooling-sdk/cli';
98
import {removeMember} from '@salesforce/b2c-tooling-sdk/operations/mrt';
109
import {t, withDocs} from '../../../../i18n/index.js';
11-
12-
/**
13-
* Prompt for confirmation.
14-
*/
15-
async function confirm(message: string): Promise<boolean> {
16-
const rl = readline.createInterface({
17-
input: process.stdin,
18-
output: process.stdout,
19-
});
20-
21-
return new Promise((resolve) => {
22-
rl.question(`${message} (y/N): `, (answer) => {
23-
rl.close();
24-
resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
25-
});
26-
});
27-
}
10+
import {confirm} from '../../../../prompts.js';
2811

2912
/**
3013
* Remove a member from an MRT project.

packages/b2c-cli/src/commands/mrt/project/notification/delete.ts

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,11 @@
33
* SPDX-License-Identifier: Apache-2
44
* For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0
55
*/
6-
import * as readline from 'node:readline';
76
import {Args, Flags} from '@oclif/core';
87
import {MrtCommand} from '@salesforce/b2c-tooling-sdk/cli';
98
import {deleteNotification} from '@salesforce/b2c-tooling-sdk/operations/mrt';
109
import {t, withDocs} from '../../../../i18n/index.js';
11-
12-
/**
13-
* Prompt for confirmation.
14-
*/
15-
async function confirm(message: string): Promise<boolean> {
16-
const rl = readline.createInterface({
17-
input: process.stdin,
18-
output: process.stdout,
19-
});
20-
21-
return new Promise((resolve) => {
22-
rl.question(`${message} (y/N): `, (answer) => {
23-
rl.close();
24-
resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
25-
});
26-
});
27-
}
10+
import {confirm} from '../../../../prompts.js';
2811

2912
/**
3013
* Delete a notification from an MRT project.

0 commit comments

Comments
 (0)