generated from salesforcecli/plugin-template
-
Notifications
You must be signed in to change notification settings - Fork 13
/
display.ts
135 lines (122 loc) · 5.38 KB
/
display.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/*
* Copyright (c) 2020, 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
*/
import {
Flags,
SfCommand,
requiredOrgFlagWithDeprecations,
loglevel,
orgApiVersionFlagWithDeprecations,
} from '@salesforce/sf-plugins-core';
import { AuthInfo, Messages, Org, SfError, trimTo15 } from '@salesforce/core';
import { camelCaseToTitleCase } from '@salesforce/kit';
import { AuthFieldsFromFS, OrgDisplayReturn, ScratchOrgFields } from '../../shared/orgTypes.js';
import { getAliasByUsername } from '../../shared/utils.js';
import { getStyledValue } from '../../shared/orgHighlighter.js';
import { OrgListUtil } from '../../shared/orgListUtil.js';
Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
const messages = Messages.loadMessages('@salesforce/plugin-org', 'display');
const sharedMessages = Messages.loadMessages('@salesforce/plugin-org', 'messages');
export class OrgDisplayCommand extends SfCommand<OrgDisplayReturn> {
public static readonly summary = messages.getMessage('summary');
public static readonly description = messages.getMessage('description');
public static readonly examples = messages.getMessages('examples');
public static readonly aliases = ['force:org:display'];
public static deprecateAliases = true;
public static readonly flags = {
'target-org': requiredOrgFlagWithDeprecations,
'api-version': orgApiVersionFlagWithDeprecations,
verbose: Flags.boolean({
summary: messages.getMessage('flags.verbose.summary'),
}),
loglevel,
};
private org!: Org;
public async run(): Promise<OrgDisplayReturn> {
const { flags } = await this.parse(OrgDisplayCommand);
this.org = flags['target-org'];
this.org.getConnection(flags['api-version']);
try {
// the auth file might have a stale access token. We want to refresh it before getting the fields
await this.org.refreshAuth();
} catch (error) {
// even if this fails, we want to display the information we can read from the auth file
this.warn('unable to refresh auth for org');
}
// translate to alias if necessary
const authInfo = await AuthInfo.create({ username: this.org.getUsername() });
const fields = authInfo.getFields(true) as AuthFieldsFromFS;
const isScratchOrg = Boolean(fields.devHubUsername);
const scratchOrgInfo =
isScratchOrg && fields.orgId ? await this.getScratchOrgInformation(fields.orgId, fields.username) : {};
const returnValue: OrgDisplayReturn = {
// renamed properties
id: fields.orgId,
devHubId: fields.devHubUsername,
// copied properties
apiVersion: fields.instanceApiVersion,
accessToken: fields.accessToken,
instanceUrl: fields.instanceUrl,
username: fields.username,
clientId: fields.clientId,
password: fields.password,
...scratchOrgInfo,
// properties with more complex logic
connectedStatus: isScratchOrg
? undefined
: await OrgListUtil.determineConnectedStatusForNonScratchOrg(fields.username),
sfdxAuthUrl: flags.verbose && fields.refreshToken ? authInfo.getSfdxAuthUrl() : undefined,
alias: await getAliasByUsername(fields.username),
};
this.warn(sharedMessages.getMessage('SecurityWarning'));
this.print(returnValue);
return returnValue;
}
private print(result: OrgDisplayReturn): void {
this.log();
const tableRows = Object.entries(result)
.filter(([, value]) => value !== undefined && value !== null) // some values won't exist
.sort() // this command always alphabetizes the table rows
.map(([key, value]) => ({
key: camelCaseToTitleCase(key),
value: typeof value === 'string' ? getStyledValue(key, value) : value,
}));
this.table({
data: tableRows,
columns: [
{ key: 'key', name: 'KEY' },
{ key: 'value', name: 'VALUE' },
],
title: 'Org Description',
});
}
private async getScratchOrgInformation(orgId: string, username: string): Promise<ScratchOrgFields> {
const hubOrg = await this.org.getDevHubOrg();
// we know this is a scratch org so it must have a hubOrg and that'll have a username
const hubUsername = hubOrg?.getUsername() as string;
// this query can return multiple records that match the 15 char ID because `ScratchOrgInfo.ScratchOrg` isn't a case-sensitive field
// so we look for the record that matches the scratch org username in the auth file.
const result = (await OrgListUtil.retrieveScratchOrgInfoFromDevHub(hubUsername, [trimTo15(orgId)])).find(
(rec) => rec.SignupUsername === username
);
if (result) {
return {
status: result.Status,
devHubId: hubUsername,
expirationDate: result.ExpirationDate,
createdBy: result.CreatedBy?.Username,
edition: result.Edition ?? undefined, // null for snapshot orgs, possibly others. Marking it undefined keeps it out of json output
namespace: result.Namespace ?? undefined, // may be null on server
orgName: result.OrgName,
createdDate: result.CreatedDate,
signupUsername: result.SignupUsername,
};
}
throw new SfError(messages.getMessage('noScratchOrgInfoError', [trimTo15(orgId), hubUsername]), 'NoScratchInfo', [
messages.getMessage('noScratchOrgInfoAction'),
]);
}
}