Skip to content

Commit

Permalink
feat: add --sfdx-url-stdin flag
Browse files Browse the repository at this point in the history
  • Loading branch information
AllanOricil committed Jul 28, 2023
1 parent affa27c commit d6c9d5d
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 7 deletions.
11 changes: 10 additions & 1 deletion command-snapshot.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,17 @@
{
"command": "org:login:sfdx-url",
"plugin": "@salesforce/plugin-auth",
"flags": ["alias", "json", "loglevel", "no-prompt", "set-default", "set-default-dev-hub", "sfdx-url-file"],
"alias": ["force:auth:sfdxurl:store", "auth:sfdxurl:store"],
"flags": [
"alias",
"json",
"loglevel",
"no-prompt",
"set-default",
"set-default-dev-hub",
"sfdx-url-file",
"sfdx-url-stdin"
],
"flagChars": ["a", "d", "f", "p", "s"],
"flagAliases": [
"noprompt",
Expand Down
8 changes: 8 additions & 0 deletions messages/sfdxurl.store.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ You can also create a JSON file that has a top-level property named sfdxAuthUrl

Path to a file that contains the Salesforce DX authorization URL.

# flags.sfdx-url-stdin.summary

Read sfdx auth url from stdin

# examples

- Authorize an org using the SFDX authorization URL in the files/authFile.json file:
Expand All @@ -31,3 +35,7 @@ Path to a file that contains the Salesforce DX authorization URL.
- Similar to previous example, but set the org as your default and give it an alias MyDefaultOrg:

<%= config.bin %> <%= command.id %> --sfdx-url-file files/authFile.json --set-default --alias MyDefaultOrg

- Authorize an org reading the SFDX authorization URL from stdin:

echo 'force://PlatformCLI::[email protected]' | <%= config.bin %> <%= command.id %> --sfdx-url-stdin --set-default --alias MyDefaultOrg
24 changes: 19 additions & 5 deletions src/commands/org/login/sfdx-url.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { AuthFields, AuthInfo, Messages } from '@salesforce/core';
import { AnyJson } from '@salesforce/ts-types';
import { parseJson } from '@salesforce/kit';
import { AuthBaseCommand } from '../../../authBaseCommand';
import { read } from '../../../stdin';

Messages.importMessagesDirectory(__dirname);
const messages = Messages.loadMessages('@salesforce/plugin-auth', 'sfdxurl.store');
Expand All @@ -22,19 +23,26 @@ type AuthJson = AnyJson & {
result?: AnyJson & { sfdxAuthUrl: string };
sfdxAuthUrl: string;
};

export default class LoginSfdxUrl extends AuthBaseCommand<AuthFields> {
public static readonly summary = messages.getMessage('summary');
public static readonly description = messages.getMessage('description', [AUTH_URL_FORMAT]);
public static readonly examples = messages.getMessages('examples');
public static aliases = ['force:auth:sfdxurl:store', 'auth:sfdxurl:store'];

public static readonly flags = {
'sfdx-url-stdin': Flags.boolean({
summary: messages.getMessage('flags.sfdx-url-stdin.summary'),
exclusive: ['sfdx-url-file'],
exactlyOne: ['sfdx-url-file'],
}),
'sfdx-url-file': Flags.file({
char: 'f',
summary: messages.getMessage('flags.sfdx-url-file.summary'),
required: true,
deprecateAliases: true,
aliases: ['sfdxurlfile'],
exclusive: ['sfdx-url-stdin'],
exactlyOne: ['sfdx-url-stdin'],
}),
'set-default-dev-hub': Flags.boolean({
char: 'd',
Expand Down Expand Up @@ -67,15 +75,21 @@ export default class LoginSfdxUrl extends AuthBaseCommand<AuthFields> {

public async run(): Promise<AuthFields> {
const { flags } = await this.parse(LoginSfdxUrl);
if (await this.shouldExitCommand(flags['no-prompt'])) return {};

const authFile = flags['sfdx-url-file'];
if (await this.shouldExitCommand(flags['no-prompt'])) return {};

const sfdxAuthUrl = authFile.endsWith('.json') ? await getUrlFromJson(authFile) : await readFile(authFile, 'utf8');
const sfdxUrlFile = flags['sfdx-url-file'];
const sfdxAuthUrl = flags['sfdx-url-stdin']
? await read()
: sfdxUrlFile
? sfdxUrlFile.endsWith('.json')
? await getUrlFromJson(sfdxUrlFile)
: await readFile(sfdxUrlFile, 'utf8')
: null;

if (!sfdxAuthUrl) {
throw new Error(
`Error getting the auth URL from file ${authFile}. Please ensure it meets the description shown in the documentation for this command.`
'Error retrieving the auth URL. Please ensure it meets the description shown in the documentation for this command.'
);
}

Expand Down
25 changes: 25 additions & 0 deletions src/stdin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright (c) 2023, salesforce.com, inc.
* All rights reserved.
* Licensed under the BSD 3-Clause license.
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/
export function read(): Promise<string | undefined> {
return new Promise((resolve) => {
const stdin = process.openStdin();
stdin.setEncoding('utf-8');

let data = '';
stdin.on('data', (chunk) => {
data += chunk;
});

stdin.on('end', () => {
resolve(data);
});

if (stdin.isTTY) {
resolve('');
}
});
}
8 changes: 8 additions & 0 deletions test/commands/org/login/login.sfdx-url.nut.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,12 @@ describe('org:login:sfdx-url NUTs', () => {
const output = getString(result, 'shellOutput.stdout');
expect(output).to.include(`Successfully authorized ${username} with org ID`);
});

it('should authorize an org using sfdx-url (human readable)', () => {
env.setString('TESTKIT_EXECUTABLE_PATH', `echo '${authUrl}' | ${env.getString('TESTKIT_EXECUTABLE_PATH')}`);
const command = 'org:login:sfdx-url -d --sfdx-url-stdin';
const result = execCmd(command, { ensureExitCode: 0 });
const output = getString(result, 'shellOutput.stdout');
expect(output).to.include(`Successfully authorized ${username} with org ID`);
});
});
22 changes: 21 additions & 1 deletion test/commands/org/login/login.sfdx-url.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { Config } from '@oclif/core';
import { StubbedType, stubInterface } from '@salesforce/ts-sinon';
import { SfCommand } from '@salesforce/sf-plugins-core';
import LoginSfdxUrl from '../../../../src/commands/org/login/sfdx-url';
import * as stdin from '../../../../src/stdin';

interface Options {
authInfoCreateFails?: boolean;
Expand Down Expand Up @@ -91,7 +92,7 @@ describe('org:login:sfdx-url', () => {
const response = await store.run();
expect.fail(`Should have thrown an error. Response: ${JSON.stringify(response)}`);
} catch (e) {
expect((e as Error).message).to.includes('Error getting the auth URL from file');
expect((e as Error).message).to.includes('Error retrieving the auth URL');
}
});

Expand Down Expand Up @@ -213,4 +214,23 @@ describe('org:login:sfdx-url', () => {
await store.run();
expect(authInfoStub.save.callCount).to.equal(1);
});

it('should return auth fields when reading auth url from stdin', async () => {
await prepareStubs({ fileDoesNotExist: true });
$$.SANDBOX.stub(stdin, 'read').resolves('force://PlatformCLI::[email protected]');
const store = new LoginSfdxUrl(['--sfdx-url-stdin', '--json'], {} as Config);
const response = await store.run();
expect(response.username).to.equal(testData.username);
});

it('should throw error when passing both sfdx-url-stdin and sfdx-url-file', async () => {
const store = new LoginSfdxUrl(['--sfdx-url-stdin', '--sfdx-url-file', 'path/to/key.txt', '--json'], {} as Config);

try {
const response = await store.run();
expect.fail(`Should have thrown an error. Response: ${JSON.stringify(response)}`);
} catch (e) {
expect((e as Error).message).to.includes('--sfdx-url-file cannot also be provided when using --sfdx-url-stdin');
}
});
});

0 comments on commit d6c9d5d

Please sign in to comment.