@salesforce/core 3.13.0 → 3.15.0
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/CHANGELOG.md +18 -0
- package/lib/config/config.d.ts +23 -1
- package/lib/config/config.js +28 -18
- package/lib/config/configAggregator.d.ts +37 -24
- package/lib/config/configAggregator.js +83 -41
- package/lib/config/envVars.js +3 -3
- package/lib/config/sandboxProcessCache.d.ts +15 -0
- package/lib/config/sandboxProcessCache.js +38 -0
- package/lib/exported.d.ts +5 -3
- package/lib/exported.js +8 -2
- package/lib/globalInfo/accessors/sandboxAccessor.d.ts +36 -0
- package/lib/globalInfo/accessors/sandboxAccessor.js +63 -0
- package/lib/globalInfo/globalInfoConfig.d.ts +2 -0
- package/lib/globalInfo/globalInfoConfig.js +5 -0
- package/lib/globalInfo/sfdxDataHandler.d.ts +12 -2
- package/lib/globalInfo/sfdxDataHandler.js +116 -25
- package/lib/globalInfo/types.d.ts +19 -1
- package/lib/globalInfo/types.js +1 -0
- package/lib/org/authInfo.d.ts +2 -1
- package/lib/org/authInfo.js +2 -1
- package/lib/org/connection.js +4 -4
- package/lib/org/org.d.ts +61 -39
- package/lib/org/org.js +261 -159
- package/lib/org/scratchOrgCache.d.ts +19 -0
- package/lib/org/scratchOrgCache.js +33 -0
- package/lib/org/scratchOrgCreate.d.ts +25 -16
- package/lib/org/scratchOrgCreate.js +110 -41
- package/lib/org/scratchOrgErrorCodes.d.ts +8 -2
- package/lib/org/scratchOrgErrorCodes.js +26 -3
- package/lib/org/scratchOrgInfoApi.d.ts +19 -8
- package/lib/org/scratchOrgInfoApi.js +91 -42
- package/lib/org/scratchOrgLifecycleEvents.d.ts +2 -0
- package/lib/org/scratchOrgLifecycleEvents.js +20 -1
- package/lib/org/scratchOrgSettingsGenerator.d.ts +7 -2
- package/lib/org/scratchOrgSettingsGenerator.js +1 -0
- package/lib/sfProject.js +1 -1
- package/lib/status/pollingClient.js +1 -0
- package/lib/testSetup.js +0 -2
- package/messages/org.md +9 -1
- package/messages/scratchOrgCreate.md +20 -0
- package/package.json +2 -2
package/lib/org/org.js
CHANGED
|
@@ -14,7 +14,6 @@ const ts_types_1 = require("@salesforce/ts-types");
|
|
|
14
14
|
const config_1 = require("../config/config");
|
|
15
15
|
const configAggregator_1 = require("../config/configAggregator");
|
|
16
16
|
const orgUsersConfig_1 = require("../config/orgUsersConfig");
|
|
17
|
-
const sandboxOrgConfig_1 = require("../config/sandboxOrgConfig");
|
|
18
17
|
const global_1 = require("../global");
|
|
19
18
|
const lifecycleEvents_1 = require("../lifecycleEvents");
|
|
20
19
|
const logger_1 = require("../logger");
|
|
@@ -23,6 +22,7 @@ const sfdc_1 = require("../util/sfdc");
|
|
|
23
22
|
const webOAuthServer_1 = require("../webOAuthServer");
|
|
24
23
|
const messages_1 = require("../messages");
|
|
25
24
|
const globalInfo_1 = require("../globalInfo");
|
|
25
|
+
const pollingClient_1 = require("../status/pollingClient");
|
|
26
26
|
const connection_1 = require("./connection");
|
|
27
27
|
const authInfo_1 = require("./authInfo");
|
|
28
28
|
const scratchOrgCreate_1 = require("./scratchOrgCreate");
|
|
@@ -35,11 +35,12 @@ const messages = messages_1.Messages.load('@salesforce/core', 'org', [
|
|
|
35
35
|
'noDevHubFound',
|
|
36
36
|
'notADevHub',
|
|
37
37
|
'noUsernameFound',
|
|
38
|
-
'orgPollingTimeout',
|
|
39
38
|
'sandboxDeleteFailed',
|
|
40
39
|
'sandboxInfoCreateFailed',
|
|
41
40
|
'sandboxNotFound',
|
|
42
41
|
'scratchOrgNotFound',
|
|
42
|
+
'AuthInfoOrgIdUndefined',
|
|
43
|
+
'sandboxCreateNotComplete',
|
|
43
44
|
]);
|
|
44
45
|
var OrgTypes;
|
|
45
46
|
(function (OrgTypes) {
|
|
@@ -52,6 +53,7 @@ var SandboxEvents;
|
|
|
52
53
|
SandboxEvents["EVENT_ASYNC_RESULT"] = "asyncResult";
|
|
53
54
|
SandboxEvents["EVENT_RESULT"] = "result";
|
|
54
55
|
SandboxEvents["EVENT_AUTH"] = "auth";
|
|
56
|
+
SandboxEvents["EVENT_RESUME"] = "resume";
|
|
55
57
|
})(SandboxEvents = exports.SandboxEvents || (exports.SandboxEvents = {}));
|
|
56
58
|
/**
|
|
57
59
|
* Provides a way to manage a locally authenticated Org.
|
|
@@ -95,23 +97,88 @@ class Org extends kit_1.AsyncOptionalCreatable {
|
|
|
95
97
|
* @param sandboxReq SandboxRequest options to create the sandbox with
|
|
96
98
|
* @param options Wait: The amount of time to wait before timing out, Interval: The time interval between polling
|
|
97
99
|
*/
|
|
98
|
-
async createSandbox(sandboxReq, options
|
|
99
|
-
|
|
100
|
-
|
|
100
|
+
async createSandbox(sandboxReq, options = {
|
|
101
|
+
wait: kit_1.Duration.minutes(6),
|
|
102
|
+
async: false,
|
|
103
|
+
interval: kit_1.Duration.seconds(30),
|
|
104
|
+
}) {
|
|
105
|
+
this.logger.debug('CreateSandbox called with SandboxRequest:', sandboxReq);
|
|
101
106
|
const createResult = await this.connection.tooling.create('SandboxInfo', sandboxReq);
|
|
102
|
-
this.logger.debug('Return from calling tooling.create:
|
|
107
|
+
this.logger.debug('Return from calling tooling.create:', createResult);
|
|
103
108
|
if (Array.isArray(createResult) || !createResult.success) {
|
|
104
109
|
throw messages.createError('sandboxInfoCreateFailed', [JSON.stringify(createResult)]);
|
|
105
110
|
}
|
|
106
|
-
const sandboxCreationProgress = await this.
|
|
107
|
-
this.logger.debug('Return from calling singleRecordQuery with tooling:
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
+
const sandboxCreationProgress = await this.querySandboxProcessBySandboxInfoId(createResult.id);
|
|
112
|
+
this.logger.debug('Return from calling singleRecordQuery with tooling:', sandboxCreationProgress);
|
|
113
|
+
const isAsync = !!options.async;
|
|
114
|
+
if (isAsync) {
|
|
115
|
+
// The user didn't want us to poll, so simply return the status
|
|
116
|
+
await lifecycleEvents_1.Lifecycle.getInstance().emit(SandboxEvents.EVENT_ASYNC_RESULT, sandboxCreationProgress);
|
|
117
|
+
return sandboxCreationProgress;
|
|
118
|
+
}
|
|
119
|
+
const [wait, pollInterval] = this.validateWaitOptions(options);
|
|
120
|
+
this.logger.debug(`create - pollStatusAndAuth sandboxProcessObj, max wait time of ${wait.minutes} minutes`, sandboxCreationProgress);
|
|
121
|
+
return this.pollStatusAndAuth({
|
|
122
|
+
sandboxProcessObj: sandboxCreationProgress,
|
|
123
|
+
wait,
|
|
124
|
+
pollInterval,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* resume a sandbox creation from a production org
|
|
129
|
+
* 'this' needs to be a production org with sandbox licenses available
|
|
130
|
+
*
|
|
131
|
+
* @param resumeSandboxRequest SandboxRequest options to create the sandbox with
|
|
132
|
+
* @param options Wait: The amount of time to wait (default: 30 minutes) before timing out,
|
|
133
|
+
* Interval: The time interval (default: 30 seconds) between polling
|
|
134
|
+
*/
|
|
135
|
+
async resumeSandbox(resumeSandboxRequest, options = {
|
|
136
|
+
wait: kit_1.Duration.minutes(0),
|
|
137
|
+
async: false,
|
|
138
|
+
interval: kit_1.Duration.seconds(30),
|
|
139
|
+
}) {
|
|
140
|
+
var _a;
|
|
141
|
+
this.logger.debug('ResumeSandbox called with ResumeSandboxRequest:', resumeSandboxRequest);
|
|
142
|
+
let sandboxCreationProgress;
|
|
143
|
+
// seed the sandboxCreationProgress via the resumeSandboxRequest options
|
|
144
|
+
if (resumeSandboxRequest.SandboxName) {
|
|
145
|
+
sandboxCreationProgress = await this.querySandboxProcessBySandboxName(resumeSandboxRequest.SandboxName);
|
|
146
|
+
}
|
|
147
|
+
else if (resumeSandboxRequest.SandboxProcessObjId) {
|
|
148
|
+
sandboxCreationProgress = await this.querySandboxProcessById(resumeSandboxRequest.SandboxProcessObjId);
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
throw messages.createError('sandboxNotFound', [
|
|
152
|
+
(_a = resumeSandboxRequest.SandboxName) !== null && _a !== void 0 ? _a : resumeSandboxRequest.SandboxProcessObjId,
|
|
153
|
+
]);
|
|
154
|
+
}
|
|
155
|
+
this.logger.debug('Return from calling singleRecordQuery with tooling:', sandboxCreationProgress);
|
|
156
|
+
await lifecycleEvents_1.Lifecycle.getInstance().emit(SandboxEvents.EVENT_RESUME, sandboxCreationProgress);
|
|
157
|
+
const [wait, pollInterval] = this.validateWaitOptions(options);
|
|
158
|
+
// if wait is 0, return the sandboxCreationProgress immediately
|
|
159
|
+
if (wait.seconds === 0) {
|
|
160
|
+
if (sandboxCreationProgress.Status === 'Completed') {
|
|
161
|
+
// check to see if sandbox can authenticate via sandboxAuth endpoint
|
|
162
|
+
const sandboxInfo = await this.sandboxSignupComplete(sandboxCreationProgress);
|
|
163
|
+
if (sandboxInfo) {
|
|
164
|
+
await lifecycleEvents_1.Lifecycle.getInstance().emit(SandboxEvents.EVENT_AUTH, sandboxInfo);
|
|
165
|
+
try {
|
|
166
|
+
this.logger.debug('sandbox signup complete with', sandboxInfo);
|
|
167
|
+
await this.writeSandboxAuthFile(sandboxCreationProgress, sandboxInfo);
|
|
168
|
+
return sandboxCreationProgress;
|
|
169
|
+
}
|
|
170
|
+
catch (err) {
|
|
171
|
+
// eat the error, we don't want to throw an error if we can't write the file
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
await lifecycleEvents_1.Lifecycle.getInstance().emit(SandboxEvents.EVENT_ASYNC_RESULT, sandboxCreationProgress);
|
|
176
|
+
throw messages.createError('sandboxCreateNotComplete');
|
|
177
|
+
}
|
|
178
|
+
this.logger.debug(`resume - pollStatusAndAuth sandboxProcessObj, max wait time of ${wait.minutes} minutes`, sandboxCreationProgress);
|
|
111
179
|
return this.pollStatusAndAuth({
|
|
112
180
|
sandboxProcessObj: sandboxCreationProgress,
|
|
113
|
-
|
|
114
|
-
shouldPoll: retries > 0,
|
|
181
|
+
wait,
|
|
115
182
|
pollInterval,
|
|
116
183
|
});
|
|
117
184
|
}
|
|
@@ -156,9 +223,7 @@ class Org extends kit_1.AsyncOptionalCreatable {
|
|
|
156
223
|
return await orgUsersConfig_1.OrgUsersConfig.create(orgUsersConfig_1.OrgUsersConfig.getOptions(this.getOrgId()));
|
|
157
224
|
}
|
|
158
225
|
/**
|
|
159
|
-
*
|
|
160
|
-
* files, all user auth files for the org, matching default config settings, and any
|
|
161
|
-
* matching aliases.
|
|
226
|
+
* Cleans up all org related artifacts including users, sandbox config(if a sandbox and auth file.
|
|
162
227
|
*
|
|
163
228
|
* @param throwWhenRemoveFails Determines if the call should throw an error or fail silently.
|
|
164
229
|
*/
|
|
@@ -168,7 +233,7 @@ class Org extends kit_1.AsyncOptionalCreatable {
|
|
|
168
233
|
if (this.getConnection().isUsingAccessToken()) {
|
|
169
234
|
return Promise.resolve();
|
|
170
235
|
}
|
|
171
|
-
await this.removeSandboxConfig(
|
|
236
|
+
await this.removeSandboxConfig();
|
|
172
237
|
await this.removeUsers(throwWhenRemoveFails);
|
|
173
238
|
await this.removeUsersConfig();
|
|
174
239
|
// An attempt to remove this org's auth file occurs in this.removeUsersConfig. That's because this org's usersname is also
|
|
@@ -182,7 +247,7 @@ class Org extends kit_1.AsyncOptionalCreatable {
|
|
|
182
247
|
*
|
|
183
248
|
*/
|
|
184
249
|
async isSandbox() {
|
|
185
|
-
return
|
|
250
|
+
return (await globalInfo_1.GlobalInfo.getInstance()).sandboxes.has(this.getOrgId());
|
|
186
251
|
}
|
|
187
252
|
/**
|
|
188
253
|
* Check that this org is a scratch org by asking the dev hub if it knows about it.
|
|
@@ -491,25 +556,22 @@ class Org extends kit_1.AsyncOptionalCreatable {
|
|
|
491
556
|
return this;
|
|
492
557
|
}
|
|
493
558
|
/**
|
|
494
|
-
*
|
|
495
|
-
*
|
|
559
|
+
* set the sandbox config related to this given org
|
|
496
560
|
*
|
|
497
|
-
* @param {
|
|
498
|
-
* @param {
|
|
561
|
+
* @param orgId {string} orgId of the sandbox
|
|
562
|
+
* @param config {SfSandbox} config of the sandbox
|
|
499
563
|
*/
|
|
500
|
-
async
|
|
501
|
-
|
|
502
|
-
sandboxOrgConfig.set(field, value);
|
|
503
|
-
await sandboxOrgConfig.write();
|
|
564
|
+
async setSandboxConfig(orgId, config) {
|
|
565
|
+
(await globalInfo_1.GlobalInfo.getInstance()).sandboxes.set(orgId, config);
|
|
504
566
|
return this;
|
|
505
567
|
}
|
|
506
568
|
/**
|
|
507
|
-
*
|
|
569
|
+
* get the sandbox config for the given orgId
|
|
570
|
+
*
|
|
571
|
+
* @param orgId {string} orgId of the sandbox
|
|
508
572
|
*/
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
const sandboxOrgConfig = await this.retrieveSandboxOrgConfig();
|
|
512
|
-
return sandboxOrgConfig.get(field);
|
|
573
|
+
async getSandboxConfig(orgId) {
|
|
574
|
+
return (await globalInfo_1.GlobalInfo.getInstance()).sandboxes.get(orgId);
|
|
513
575
|
}
|
|
514
576
|
/**
|
|
515
577
|
* Retrieves the highest api version that is supported by the target server instance. If the apiVersion configured for
|
|
@@ -566,6 +628,53 @@ class Org extends kit_1.AsyncOptionalCreatable {
|
|
|
566
628
|
getConnection() {
|
|
567
629
|
return this.connection;
|
|
568
630
|
}
|
|
631
|
+
async supportsSourceTracking() {
|
|
632
|
+
if (this.isScratch()) {
|
|
633
|
+
return true;
|
|
634
|
+
}
|
|
635
|
+
const conn = this.getConnection();
|
|
636
|
+
try {
|
|
637
|
+
await conn.tooling.sobject('SourceMember').describe();
|
|
638
|
+
return true;
|
|
639
|
+
}
|
|
640
|
+
catch (err) {
|
|
641
|
+
if (err.message.includes('The requested resource does not exist')) {
|
|
642
|
+
return false;
|
|
643
|
+
}
|
|
644
|
+
throw err;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
/**
|
|
648
|
+
* query SandboxProcess via sandbox name
|
|
649
|
+
*
|
|
650
|
+
* @param name SandboxName to query for
|
|
651
|
+
* @private
|
|
652
|
+
*/
|
|
653
|
+
async querySandboxProcessBySandboxName(name) {
|
|
654
|
+
return await this.querySandboxProcess(`SandboxName='${name}'`);
|
|
655
|
+
}
|
|
656
|
+
/**
|
|
657
|
+
* query SandboxProcess via SandboxInfoId
|
|
658
|
+
*
|
|
659
|
+
* @param id SandboxInfoId to query for
|
|
660
|
+
* @private
|
|
661
|
+
*/
|
|
662
|
+
async querySandboxProcessBySandboxInfoId(id) {
|
|
663
|
+
return await this.querySandboxProcess(`SandboxInfoId='${id}'`);
|
|
664
|
+
const queryStr = `SELECT Id, Status, SandboxName, SandboxInfoId, LicenseType, CreatedDate, CopyProgress, SandboxOrganization, SourceId, Description, EndDate FROM SandboxProcess WHERE SandboxInfoId='${id}' AND Status != 'D'`;
|
|
665
|
+
return await this.connection.singleRecordQuery(queryStr, {
|
|
666
|
+
tooling: true,
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
/**
|
|
670
|
+
* query SandboxProcess via Id
|
|
671
|
+
*
|
|
672
|
+
* @param id SandboxProcessId to query for
|
|
673
|
+
* @private
|
|
674
|
+
*/
|
|
675
|
+
async querySandboxProcessById(id) {
|
|
676
|
+
return await this.querySandboxProcess(`Id='${id}'`);
|
|
677
|
+
}
|
|
569
678
|
/**
|
|
570
679
|
* Initialize async components.
|
|
571
680
|
*/
|
|
@@ -617,47 +726,53 @@ class Org extends kit_1.AsyncOptionalCreatable {
|
|
|
617
726
|
* @private
|
|
618
727
|
*/
|
|
619
728
|
async deleteSandbox(prodOrg) {
|
|
729
|
+
const sandbox = await this.getSandboxConfig(this.getOrgId());
|
|
620
730
|
prodOrg !== null && prodOrg !== void 0 ? prodOrg : (prodOrg = await Org.create({
|
|
621
731
|
aggregator: this.configAggregator,
|
|
622
|
-
aliasOrUsername:
|
|
732
|
+
aliasOrUsername: sandbox === null || sandbox === void 0 ? void 0 : sandbox.prodOrgUsername,
|
|
623
733
|
}));
|
|
624
|
-
let
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
// try to calculate sandbox name from the production org
|
|
628
|
-
// production org: admin@integrationtesthub.org
|
|
629
|
-
// this.getUsername: admin@integrationtesthub.org.dev1
|
|
630
|
-
// sandboxName in Production: dev1
|
|
631
|
-
const sandboxName = (this.getUsername() || '').split(`${prodOrg.getUsername()}.`)[1];
|
|
632
|
-
if (!sandboxName) {
|
|
633
|
-
this.logger.debug('Could not construct a sandbox name');
|
|
634
|
-
throw new Error();
|
|
635
|
-
}
|
|
636
|
-
this.logger.debug(`attempting to locate sandbox with username ${sandboxName}`);
|
|
637
|
-
result = await this.queryProduction(prodOrg, 'SandboxName', sandboxName);
|
|
638
|
-
if (!result) {
|
|
639
|
-
this.logger.debug(`Failed to find sandbox with username: ${sandboxName}`);
|
|
640
|
-
throw new Error();
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
catch {
|
|
644
|
-
// if an error is thrown, don't panic yet. we'll try querying by orgId
|
|
645
|
-
const trimmedId = sfdc_1.sfdc.trimTo15(this.getOrgId());
|
|
646
|
-
this.logger.debug(`defaulting to trimming id from ${this.getOrgId()} to ${trimmedId}`);
|
|
734
|
+
let sandboxInfoId = sandbox === null || sandbox === void 0 ? void 0 : sandbox.sandboxInfoId;
|
|
735
|
+
if (!sandboxInfoId) {
|
|
736
|
+
let result;
|
|
647
737
|
try {
|
|
648
|
-
|
|
738
|
+
// grab sandboxName from config or try to calculate from the sandbox username
|
|
739
|
+
const sandboxName = (sandbox === null || sandbox === void 0 ? void 0 : sandbox.sandboxName) || (this.getUsername() || '').split(`${prodOrg.getUsername()}.`)[1];
|
|
740
|
+
if (!sandboxName) {
|
|
741
|
+
this.logger.debug('Sandbox name is not available');
|
|
742
|
+
// jump to query by orgId
|
|
743
|
+
throw new Error();
|
|
744
|
+
}
|
|
745
|
+
this.logger.debug(`attempting to locate sandbox with sandbox ${sandboxName}`);
|
|
746
|
+
try {
|
|
747
|
+
result = await this.queryProduction(prodOrg, 'SandboxName', sandboxName);
|
|
748
|
+
}
|
|
749
|
+
catch (err) {
|
|
750
|
+
this.logger.debug(`Failed to find sandbox with sandbox name: ${sandboxName}`);
|
|
751
|
+
// jump to query by orgId
|
|
752
|
+
throw err;
|
|
753
|
+
}
|
|
649
754
|
}
|
|
650
755
|
catch {
|
|
651
|
-
|
|
756
|
+
// if an error is thrown, don't panic yet. we'll try querying by orgId
|
|
757
|
+
const trimmedId = sfdc_1.sfdc.trimTo15(this.getOrgId());
|
|
758
|
+
this.logger.debug(`defaulting to trimming id from ${this.getOrgId()} to ${trimmedId}`);
|
|
759
|
+
try {
|
|
760
|
+
result = await this.queryProduction(prodOrg, 'SandboxOrganization', trimmedId);
|
|
761
|
+
sandboxInfoId = result.SandboxInfoId;
|
|
762
|
+
}
|
|
763
|
+
catch {
|
|
764
|
+
// eating exceptions when trying to find sandbox process record by orgId
|
|
765
|
+
// allows idempotent cleanup of sandbox orgs
|
|
766
|
+
this.logger.debug(`Failed find a SandboxProcess for the sandbox org: ${this.getOrgId()}`);
|
|
767
|
+
}
|
|
652
768
|
}
|
|
653
769
|
}
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
await this.remove();
|
|
658
|
-
if (Array.isArray(deleteResult) || !deleteResult.success) {
|
|
659
|
-
throw messages.createError('sandboxDeleteFailed', [JSON.stringify(deleteResult)]);
|
|
770
|
+
if (sandboxInfoId) {
|
|
771
|
+
const deleteResult = await this.destroySandbox(prodOrg, sandboxInfoId);
|
|
772
|
+
this.logger.debug('Return from calling tooling.delete: ', deleteResult);
|
|
660
773
|
}
|
|
774
|
+
// cleanup remaining artifacts
|
|
775
|
+
await this.remove();
|
|
661
776
|
}
|
|
662
777
|
/**
|
|
663
778
|
* If this Org is a scratch org, calling this method will delete the scratch org from the DevHub and clean up any local files
|
|
@@ -725,12 +840,6 @@ class Org extends kit_1.AsyncOptionalCreatable {
|
|
|
725
840
|
await config.unlink();
|
|
726
841
|
}
|
|
727
842
|
}
|
|
728
|
-
/**
|
|
729
|
-
* @ignore
|
|
730
|
-
*/
|
|
731
|
-
async retrieveSandboxOrgConfig() {
|
|
732
|
-
return await sandboxOrgConfig_1.SandboxOrgConfig.create(sandboxOrgConfig_1.SandboxOrgConfig.getOptions(this.getOrgId()));
|
|
733
|
-
}
|
|
734
843
|
async manageDelete(cb, dirPath, throwWhenRemoveFails) {
|
|
735
844
|
return cb().catch((e) => {
|
|
736
845
|
if (throwWhenRemoveFails) {
|
|
@@ -775,22 +884,16 @@ class Org extends kit_1.AsyncOptionalCreatable {
|
|
|
775
884
|
}));
|
|
776
885
|
await globalInfo.write();
|
|
777
886
|
}
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
*/
|
|
783
|
-
async removeSandboxConfig(throwWhenRemoveFails) {
|
|
784
|
-
const sandboxOrgConfig = await this.retrieveSandboxOrgConfig();
|
|
785
|
-
if (await sandboxOrgConfig.exists()) {
|
|
786
|
-
await this.manageDelete(async () => await sandboxOrgConfig.unlink(), sandboxOrgConfig.getPath(), throwWhenRemoveFails);
|
|
787
|
-
}
|
|
887
|
+
async removeSandboxConfig() {
|
|
888
|
+
const globalInfo = await globalInfo_1.GlobalInfo.getInstance();
|
|
889
|
+
globalInfo.sandboxes.unset(this.getOrgId());
|
|
890
|
+
await globalInfo.write();
|
|
788
891
|
}
|
|
789
892
|
async writeSandboxAuthFile(sandboxProcessObj, sandboxRes) {
|
|
790
|
-
this.logger.debug(
|
|
893
|
+
this.logger.debug(`writeSandboxAuthFile sandboxProcessObj: ${JSON.stringify(sandboxProcessObj)}, sandboxRes: ${JSON.stringify(sandboxRes)}`);
|
|
791
894
|
if (sandboxRes.authUserName) {
|
|
792
895
|
const productionAuthFields = this.connection.getAuthInfoFields();
|
|
793
|
-
this.logger.debug('Result from getAuthInfoFields: AuthFields
|
|
896
|
+
this.logger.debug('Result from getAuthInfoFields: AuthFields', productionAuthFields);
|
|
794
897
|
// let's do headless auth via jwt (if we have privateKey) or web auth
|
|
795
898
|
const oauth2Options = {
|
|
796
899
|
loginUrl: sandboxRes.loginUrl,
|
|
@@ -802,16 +905,34 @@ class Org extends kit_1.AsyncOptionalCreatable {
|
|
|
802
905
|
oauth2Options.redirectUri = `http://localhost:${await webOAuthServer_1.WebOAuthServer.determineOauthPort()}/OauthRedirect`;
|
|
803
906
|
oauth2Options.authCode = sandboxRes.authCode;
|
|
804
907
|
}
|
|
908
|
+
else {
|
|
909
|
+
oauth2Options.privateKey = productionAuthFields.privateKey;
|
|
910
|
+
oauth2Options.clientId = productionAuthFields.clientId;
|
|
911
|
+
}
|
|
805
912
|
const authInfo = await authInfo_1.AuthInfo.create({
|
|
806
913
|
username: sandboxRes.authUserName,
|
|
807
914
|
oauth2Options,
|
|
808
915
|
parentUsername: productionAuthFields.username,
|
|
809
916
|
});
|
|
917
|
+
this.logger.debug('Creating AuthInfo for sandbox', sandboxRes.authUserName, productionAuthFields.username, oauth2Options);
|
|
918
|
+
// save auth info for new sandbox
|
|
810
919
|
await authInfo.save();
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
920
|
+
if (!authInfo.getFields().orgId) {
|
|
921
|
+
throw messages.createError('AuthInfoOrgIdUndefined');
|
|
922
|
+
}
|
|
923
|
+
// set the sandbox config value
|
|
924
|
+
const sfSandbox = {
|
|
925
|
+
sandboxUsername: sandboxRes.authUserName,
|
|
926
|
+
sandboxOrgId: authInfo.getFields().orgId,
|
|
927
|
+
prodOrgUsername: this.getUsername(),
|
|
928
|
+
sandboxName: sandboxProcessObj.SandboxName,
|
|
929
|
+
sandboxProcessId: sandboxProcessObj.Id,
|
|
930
|
+
sandboxInfoId: sandboxProcessObj.SandboxInfoId,
|
|
931
|
+
timestamp: new Date().toISOString(),
|
|
932
|
+
};
|
|
933
|
+
await this.setSandboxConfig(authInfo.getFields().orgId, sfSandbox);
|
|
934
|
+
const globalInfo = await globalInfo_1.GlobalInfo.getInstance();
|
|
935
|
+
await globalInfo.write();
|
|
815
936
|
await lifecycleEvents_1.Lifecycle.getInstance().emit(SandboxEvents.EVENT_RESULT, {
|
|
816
937
|
sandboxProcessObj,
|
|
817
938
|
sandboxRes,
|
|
@@ -822,84 +943,56 @@ class Org extends kit_1.AsyncOptionalCreatable {
|
|
|
822
943
|
throw messages.createError('missingAuthUsername', [sandboxProcessObj.SandboxName]);
|
|
823
944
|
}
|
|
824
945
|
}
|
|
825
|
-
/**
|
|
826
|
-
* Polls for the new sandbox to be created - and will write the associated auth files
|
|
827
|
-
*
|
|
828
|
-
* @private
|
|
829
|
-
* @param options
|
|
830
|
-
* sandboxProcessObj: The in-progress sandbox signup request
|
|
831
|
-
* retries: the number of retries to poll for every 30s
|
|
832
|
-
* shouldPoll: wait for polling, or just return
|
|
833
|
-
* pollInterval: Duration to sleep between poll events, default 30 seconds
|
|
834
|
-
*/
|
|
835
946
|
async pollStatusAndAuth(options) {
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
this.logger.debug('PollStatusAndAuth called with SandboxProcessObject%s, retries %s', sandboxProcessObj, retries);
|
|
839
|
-
const lifecycle = lifecycleEvents_1.Lifecycle.getInstance();
|
|
840
|
-
let pollFinished = false;
|
|
947
|
+
this.logger.debug('PollStatusAndAuth called with SandboxProcessObject', options.sandboxProcessObj, options.wait.minutes, options.pollInterval.seconds);
|
|
948
|
+
let remainingWait = options.wait;
|
|
841
949
|
let waitingOnAuth = false;
|
|
842
|
-
const
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
await this.
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
950
|
+
const pollingClient = await pollingClient_1.PollingClient.create({
|
|
951
|
+
poll: async () => {
|
|
952
|
+
var _a;
|
|
953
|
+
const sandboxProcessObj = await this.querySandboxProcessBySandboxInfoId(options.sandboxProcessObj.SandboxInfoId);
|
|
954
|
+
// check to see if sandbox can authenticate via sandboxAuth endpoint
|
|
955
|
+
const sandboxInfo = await this.sandboxSignupComplete(sandboxProcessObj);
|
|
956
|
+
if (sandboxInfo) {
|
|
957
|
+
await lifecycleEvents_1.Lifecycle.getInstance().emit(SandboxEvents.EVENT_AUTH, sandboxInfo);
|
|
958
|
+
try {
|
|
959
|
+
this.logger.debug('sandbox signup complete with', sandboxInfo);
|
|
960
|
+
await this.writeSandboxAuthFile(sandboxProcessObj, sandboxInfo);
|
|
961
|
+
return { completed: true, payload: sandboxProcessObj };
|
|
962
|
+
}
|
|
963
|
+
catch (err) {
|
|
964
|
+
const error = err;
|
|
965
|
+
this.logger.debug('Exception while calling writeSandboxAuthFile', err);
|
|
966
|
+
if ((error === null || error === void 0 ? void 0 : error.name) === 'JwtAuthError' && ((_a = error === null || error === void 0 ? void 0 : error.stack) === null || _a === void 0 ? void 0 : _a.includes("user hasn't approved"))) {
|
|
967
|
+
waitingOnAuth = true;
|
|
968
|
+
}
|
|
969
|
+
else {
|
|
970
|
+
throw sfError_1.SfError.wrap(error);
|
|
971
|
+
}
|
|
972
|
+
}
|
|
858
973
|
}
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
await Promise.all([
|
|
865
|
-
await lifecycle.emit(SandboxEvents.EVENT_STATUS, {
|
|
866
|
-
sandboxProcessObj,
|
|
867
|
-
interval: pollInterval.seconds,
|
|
868
|
-
retries,
|
|
869
|
-
waitingOnAuth,
|
|
870
|
-
}),
|
|
871
|
-
await (0, kit_1.sleep)(pollInterval),
|
|
872
|
-
]);
|
|
873
|
-
const polledSandboxProcessObj = await this.querySandboxProcess(sandboxProcessObj.SandboxInfoId);
|
|
874
|
-
return this.pollStatusAndAuth({
|
|
875
|
-
sandboxProcessObj: polledSandboxProcessObj,
|
|
876
|
-
retries: retries - 1,
|
|
877
|
-
shouldPoll,
|
|
878
|
-
pollInterval,
|
|
974
|
+
await lifecycleEvents_1.Lifecycle.getInstance().emit(SandboxEvents.EVENT_STATUS, {
|
|
975
|
+
sandboxProcessObj,
|
|
976
|
+
remainingWait: remainingWait.seconds,
|
|
977
|
+
interval: options.pollInterval.seconds,
|
|
978
|
+
waitingOnAuth,
|
|
879
979
|
});
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
// The user didn't want us to poll, so simply return the status
|
|
888
|
-
// simply report status and exit
|
|
889
|
-
await lifecycle.emit(SandboxEvents.EVENT_ASYNC_RESULT, sandboxProcessObj);
|
|
890
|
-
}
|
|
891
|
-
}
|
|
892
|
-
}
|
|
893
|
-
return sandboxProcessObj;
|
|
980
|
+
remainingWait = kit_1.Duration.seconds(remainingWait.seconds - options.pollInterval.seconds);
|
|
981
|
+
return { completed: false, payload: sandboxProcessObj };
|
|
982
|
+
},
|
|
983
|
+
frequency: options.pollInterval,
|
|
984
|
+
timeout: options.wait,
|
|
985
|
+
});
|
|
986
|
+
return pollingClient.subscribe();
|
|
894
987
|
}
|
|
895
988
|
/**
|
|
896
|
-
* query SandboxProcess
|
|
989
|
+
* query SandboxProcess using supplied where clause
|
|
897
990
|
*
|
|
898
|
-
* @param
|
|
991
|
+
* @param where clause to query for
|
|
899
992
|
* @private
|
|
900
993
|
*/
|
|
901
|
-
async querySandboxProcess(
|
|
902
|
-
const queryStr = `SELECT Id, Status, SandboxName, SandboxInfoId, LicenseType, CreatedDate, CopyProgress, SandboxOrganization, SourceId, Description, EndDate FROM SandboxProcess WHERE
|
|
994
|
+
async querySandboxProcess(where) {
|
|
995
|
+
const queryStr = `SELECT Id, Status, SandboxName, SandboxInfoId, LicenseType, CreatedDate, CopyProgress, SandboxOrganization, SourceId, Description, EndDate FROM SandboxProcess WHERE ${where} AND Status != 'D'`;
|
|
903
996
|
return await this.connection.singleRecordQuery(queryStr, {
|
|
904
997
|
tooling: true,
|
|
905
998
|
});
|
|
@@ -907,11 +1000,11 @@ class Org extends kit_1.AsyncOptionalCreatable {
|
|
|
907
1000
|
/**
|
|
908
1001
|
* determines if the sandbox has successfully been created
|
|
909
1002
|
*
|
|
910
|
-
* @param sandboxProcessObj sandbox signup
|
|
1003
|
+
* @param sandboxProcessObj sandbox signup progress
|
|
911
1004
|
* @private
|
|
912
1005
|
*/
|
|
913
1006
|
async sandboxSignupComplete(sandboxProcessObj) {
|
|
914
|
-
this.logger.debug('sandboxSignupComplete called with SandboxProcessObject
|
|
1007
|
+
this.logger.debug('sandboxSignupComplete called with SandboxProcessObject', sandboxProcessObj);
|
|
915
1008
|
if (!sandboxProcessObj.EndDate) {
|
|
916
1009
|
return;
|
|
917
1010
|
}
|
|
@@ -925,7 +1018,7 @@ class Org extends kit_1.AsyncOptionalCreatable {
|
|
|
925
1018
|
sandboxName: sandboxProcessObj.SandboxName,
|
|
926
1019
|
callbackUrl,
|
|
927
1020
|
};
|
|
928
|
-
this.logger.debug('Calling sandboxAuth with SandboxUserAuthRequest
|
|
1021
|
+
this.logger.debug('Calling sandboxAuth with SandboxUserAuthRequest', sandboxReq);
|
|
929
1022
|
const url = `${this.connection.tooling._baseUrl()}/sandboxAuth`;
|
|
930
1023
|
const params = {
|
|
931
1024
|
method: 'POST',
|
|
@@ -934,7 +1027,7 @@ class Org extends kit_1.AsyncOptionalCreatable {
|
|
|
934
1027
|
body: JSON.stringify(sandboxReq),
|
|
935
1028
|
};
|
|
936
1029
|
const result = await this.connection.tooling.request(params);
|
|
937
|
-
this.logger.debug('Result of calling sandboxAuth
|
|
1030
|
+
this.logger.debug('Result of calling sandboxAuth', result);
|
|
938
1031
|
return result;
|
|
939
1032
|
}
|
|
940
1033
|
catch (err) {
|
|
@@ -942,7 +1035,7 @@ class Org extends kit_1.AsyncOptionalCreatable {
|
|
|
942
1035
|
// There are cases where the endDate is set before the sandbox has actually completed.
|
|
943
1036
|
// In that case, the sandboxAuth call will throw a specific exception.
|
|
944
1037
|
if ((error === null || error === void 0 ? void 0 : error.name) === 'INVALID_STATUS') {
|
|
945
|
-
this.logger.debug('Error while authenticating the user
|
|
1038
|
+
this.logger.debug('Error while authenticating the user', error === null || error === void 0 ? void 0 : error.toString());
|
|
946
1039
|
}
|
|
947
1040
|
else {
|
|
948
1041
|
// If it fails for any unexpected reason, just pass that through
|
|
@@ -950,6 +1043,15 @@ class Org extends kit_1.AsyncOptionalCreatable {
|
|
|
950
1043
|
}
|
|
951
1044
|
}
|
|
952
1045
|
}
|
|
1046
|
+
validateWaitOptions(options) {
|
|
1047
|
+
var _a, _b;
|
|
1048
|
+
const wait = (_a = options.wait) !== null && _a !== void 0 ? _a : kit_1.Duration.minutes(30);
|
|
1049
|
+
const interval = (_b = options.interval) !== null && _b !== void 0 ? _b : kit_1.Duration.seconds(30);
|
|
1050
|
+
let pollInterval = options.async ? kit_1.Duration.seconds(0) : interval;
|
|
1051
|
+
// pollInterval cannot be > wait.
|
|
1052
|
+
pollInterval = pollInterval.seconds > wait.seconds ? wait : pollInterval;
|
|
1053
|
+
return [wait, pollInterval];
|
|
1054
|
+
}
|
|
953
1055
|
}
|
|
954
1056
|
exports.Org = Org;
|
|
955
1057
|
(function (Org) {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { JsonMap } from '@salesforce/ts-types';
|
|
2
|
+
import { TTLConfig } from '../config/ttlConfig';
|
|
3
|
+
export declare type CachedOptions = {
|
|
4
|
+
hubUsername: string;
|
|
5
|
+
/** stores the scratch definition, including settings/objectSettings */
|
|
6
|
+
definitionjson: JsonMap;
|
|
7
|
+
hubBaseUrl: string;
|
|
8
|
+
/** may be required for auth*/
|
|
9
|
+
clientSecret?: string;
|
|
10
|
+
signupTargetLoginUrlConfig?: string;
|
|
11
|
+
apiVersion?: string;
|
|
12
|
+
alias?: string;
|
|
13
|
+
setDefault?: boolean;
|
|
14
|
+
};
|
|
15
|
+
export declare class ScratchOrgCache extends TTLConfig<TTLConfig.Options, CachedOptions> {
|
|
16
|
+
static getFileName(): string;
|
|
17
|
+
static getDefaultOptions(): TTLConfig.Options;
|
|
18
|
+
static unset(key: string): Promise<void>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ScratchOrgCache = void 0;
|
|
4
|
+
/*
|
|
5
|
+
* Copyright (c) 2020, salesforce.com, inc.
|
|
6
|
+
* All rights reserved.
|
|
7
|
+
* Licensed under the BSD 3-Clause license.
|
|
8
|
+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
|
|
9
|
+
*/
|
|
10
|
+
const kit_1 = require("@salesforce/kit");
|
|
11
|
+
const global_1 = require("../global");
|
|
12
|
+
const ttlConfig_1 = require("../config/ttlConfig");
|
|
13
|
+
class ScratchOrgCache extends ttlConfig_1.TTLConfig {
|
|
14
|
+
static getFileName() {
|
|
15
|
+
return 'scratch-create-cache.json';
|
|
16
|
+
}
|
|
17
|
+
static getDefaultOptions() {
|
|
18
|
+
return {
|
|
19
|
+
isGlobal: true,
|
|
20
|
+
isState: true,
|
|
21
|
+
filename: ScratchOrgCache.getFileName(),
|
|
22
|
+
stateFolder: global_1.Global.SF_STATE_FOLDER,
|
|
23
|
+
ttl: kit_1.Duration.days(1),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
static async unset(key) {
|
|
27
|
+
const cache = await ScratchOrgCache.create();
|
|
28
|
+
cache.unset(key);
|
|
29
|
+
await cache.write();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
exports.ScratchOrgCache = ScratchOrgCache;
|
|
33
|
+
//# sourceMappingURL=scratchOrgCache.js.map
|