@salesforce/core 2.35.1 → 2.36.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 +24 -0
- package/lib/lifecycleEvents.js +1 -1
- package/lib/logger.d.ts +11 -0
- package/lib/logger.js +19 -8
- package/lib/org.js +26 -28
- package/lib/scratchOrgErrorCodes.d.ts +1 -1
- package/lib/scratchOrgErrorCodes.js +3 -0
- package/lib/scratchOrgInfoApi.d.ts +0 -1
- package/lib/scratchOrgInfoApi.js +44 -20
- package/lib/scratchOrgSettingsGenerator.js +1 -1
- package/lib/status/pollingClient.d.ts +1 -1
- package/lib/status/pollingClient.js +11 -2
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,30 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
## [2.36.0](https://github.com/forcedotcom/sfdx-core/compare/v2.35.3...v2.36.0) (2022-03-23)
|
|
6
|
+
|
|
7
|
+
### Features
|
|
8
|
+
|
|
9
|
+
- rotating log file ([d185e00](https://github.com/forcedotcom/sfdx-core/commit/d185e00aa66fc558f3c0d710cb2fafa0655a9fbc))
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
- bump jsforce types ([ddacb98](https://github.com/forcedotcom/sfdx-core/commit/ddacb987068d00aec2147130f3464232a6bdccdf))
|
|
14
|
+
- check env before resetting ([abf6ea1](https://github.com/forcedotcom/sfdx-core/commit/abf6ea1bd721f773c09f346ff9ae8d01a915e5cd))
|
|
15
|
+
|
|
16
|
+
### [2.35.3](https://github.com/forcedotcom/sfdx-core/compare/v2.35.2...v2.35.3) (2022-02-23)
|
|
17
|
+
|
|
18
|
+
### Bug Fixes
|
|
19
|
+
|
|
20
|
+
- always try to clean up aliases and configs ([cd0adc4](https://github.com/forcedotcom/sfdx-core/commit/cd0adc456978f27fc2d44cbcb61632925edcccd9))
|
|
21
|
+
|
|
22
|
+
### [2.35.2](https://github.com/forcedotcom/sfdx-core/compare/v2.35.1...v2.35.2) (2022-02-16)
|
|
23
|
+
|
|
24
|
+
### Bug Fixes
|
|
25
|
+
|
|
26
|
+
- network error tolerance ([#517](https://github.com/forcedotcom/sfdx-core/issues/517)) ([676ebfe](https://github.com/forcedotcom/sfdx-core/commit/676ebfe58b13826b53f461b2fef321c21f583004))
|
|
27
|
+
- remove redundant warnings about no listerners on warnings ([7a5bd23](https://github.com/forcedotcom/sfdx-core/commit/7a5bd2390713da929e886f41d9dcbc811104f99a))
|
|
28
|
+
|
|
5
29
|
### [2.35.1](https://github.com/forcedotcom/sfdx-core/compare/v2.35.0...v2.35.1) (2022-02-10)
|
|
6
30
|
|
|
7
31
|
### Bug Fixes
|
package/lib/lifecycleEvents.js
CHANGED
|
@@ -170,7 +170,7 @@ class Lifecycle {
|
|
|
170
170
|
*/
|
|
171
171
|
async emit(eventName, data) {
|
|
172
172
|
const listeners = this.getListeners(eventName);
|
|
173
|
-
if (listeners.length === 0) {
|
|
173
|
+
if (listeners.length === 0 && eventName !== Lifecycle.warningEventName) {
|
|
174
174
|
this.debug(`A lifecycle event with the name ${eventName} does not exist. An event must be registered before it can be emitted.`);
|
|
175
175
|
}
|
|
176
176
|
else {
|
package/lib/logger.d.ts
CHANGED
|
@@ -163,6 +163,17 @@ export declare class Logger {
|
|
|
163
163
|
static readonly LEVEL_NAMES: string[];
|
|
164
164
|
private static readonly lifecycle;
|
|
165
165
|
private static rootLogger?;
|
|
166
|
+
/**
|
|
167
|
+
* The default rotation period for logs. Example '1d' will rotate logs daily (at midnight).
|
|
168
|
+
* See 'period' docs here: https://github.com/forcedotcom/node-bunyan#stream-type-rotating-file
|
|
169
|
+
*/
|
|
170
|
+
readonly logRotationPeriod: string;
|
|
171
|
+
/**
|
|
172
|
+
* The number of backup rotated log files to keep.
|
|
173
|
+
* Example: '3' will have the base sfdx.log file, and the past 3 (period) log files.
|
|
174
|
+
* See 'count' docs here: https://github.com/forcedotcom/node-bunyan#stream-type-rotating-file
|
|
175
|
+
*/
|
|
176
|
+
readonly logRotationCount: number;
|
|
166
177
|
/**
|
|
167
178
|
* Whether debug is enabled for this Logger.
|
|
168
179
|
*/
|
package/lib/logger.js
CHANGED
|
@@ -72,6 +72,17 @@ class Logger {
|
|
|
72
72
|
* `Logger`.
|
|
73
73
|
*/
|
|
74
74
|
constructor(optionsOrName) {
|
|
75
|
+
/**
|
|
76
|
+
* The default rotation period for logs. Example '1d' will rotate logs daily (at midnight).
|
|
77
|
+
* See 'period' docs here: https://github.com/forcedotcom/node-bunyan#stream-type-rotating-file
|
|
78
|
+
*/
|
|
79
|
+
this.logRotationPeriod = new kit_1.Env().getString('SFDX_LOG_ROTATION_PERIOD') || '1d';
|
|
80
|
+
/**
|
|
81
|
+
* The number of backup rotated log files to keep.
|
|
82
|
+
* Example: '3' will have the base sfdx.log file, and the past 3 (period) log files.
|
|
83
|
+
* See 'count' docs here: https://github.com/forcedotcom/node-bunyan#stream-type-rotating-file
|
|
84
|
+
*/
|
|
85
|
+
this.logRotationCount = new kit_1.Env().getNumber('SFDX_LOG_ROTATION_COUNT') || 2;
|
|
75
86
|
/**
|
|
76
87
|
* Whether debug is enabled for this Logger.
|
|
77
88
|
*/
|
|
@@ -250,12 +261,12 @@ class Logger {
|
|
|
250
261
|
if (!this.bunyan.streams.find(
|
|
251
262
|
// No bunyan typings
|
|
252
263
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
253
|
-
(stream) => stream.type === 'file' && stream.path === logFile)) {
|
|
254
|
-
// TODO: rotating-file
|
|
255
|
-
// https://github.com/trentm/node-bunyan#stream-type-rotating-file
|
|
264
|
+
(stream) => stream.type === 'rotating-file' && stream.path === logFile)) {
|
|
256
265
|
this.addStream({
|
|
257
|
-
type: 'file',
|
|
266
|
+
type: 'rotating-file',
|
|
258
267
|
path: logFile,
|
|
268
|
+
period: this.logRotationPeriod,
|
|
269
|
+
count: this.logRotationCount,
|
|
259
270
|
level: this.bunyan.level(),
|
|
260
271
|
});
|
|
261
272
|
}
|
|
@@ -290,12 +301,12 @@ class Logger {
|
|
|
290
301
|
if (!this.bunyan.streams.find(
|
|
291
302
|
// No bunyan typings
|
|
292
303
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
293
|
-
(stream) => stream.type === 'file' && stream.path === logFile)) {
|
|
294
|
-
// TODO: rotating-file
|
|
295
|
-
// https://github.com/trentm/node-bunyan#stream-type-rotating-file
|
|
304
|
+
(stream) => stream.type === 'rotating-file' && stream.path === logFile)) {
|
|
296
305
|
this.addStream({
|
|
297
|
-
type: 'file',
|
|
306
|
+
type: 'rotating-file',
|
|
298
307
|
path: logFile,
|
|
308
|
+
period: this.logRotationPeriod,
|
|
309
|
+
count: this.logRotationCount,
|
|
299
310
|
level: this.bunyan.level(),
|
|
300
311
|
});
|
|
301
312
|
}
|
package/lib/org.js
CHANGED
|
@@ -644,35 +644,33 @@ class Org extends kit_1.AsyncCreatable {
|
|
|
644
644
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
645
645
|
async removeUsers(throwWhenRemoveFails) {
|
|
646
646
|
this.logger.debug(`Removing users associate with org: ${this.getOrgId()}`);
|
|
647
|
-
const config = await
|
|
647
|
+
const [config, authInfos, aliases] = await Promise.all([
|
|
648
|
+
this.retrieveOrgUsersConfig(),
|
|
649
|
+
this.readUserAuthFiles(),
|
|
650
|
+
aliases_1.Aliases.create(aliases_1.Aliases.getDefaultOptions()),
|
|
651
|
+
]);
|
|
648
652
|
this.logger.debug(`using path for org users: ${config.getPath()}`);
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
await config_1.Config.update(configInfo.isGlobal(), orgType, undefined);
|
|
671
|
-
}
|
|
672
|
-
await orgForUser.removeAuth();
|
|
673
|
-
}
|
|
674
|
-
await aliases.write();
|
|
675
|
-
}
|
|
653
|
+
this.logger.info(`Cleaning up usernames in org: ${this.getOrgId()}`);
|
|
654
|
+
await Promise.all(authInfos
|
|
655
|
+
.map((auth) => auth.getFields().username)
|
|
656
|
+
.map(async (username) => {
|
|
657
|
+
const aliasKeys = (username && aliases.getKeysByValue(username)) || [];
|
|
658
|
+
aliases.unsetAll(aliasKeys);
|
|
659
|
+
const orgForUser = username === this.getUsername()
|
|
660
|
+
? this
|
|
661
|
+
: await Org.create({
|
|
662
|
+
connection: await connection_1.Connection.create({ authInfo: await authInfo_1.AuthInfo.create({ username }) }),
|
|
663
|
+
});
|
|
664
|
+
const orgType = this.isDevHubOrg() ? config_1.Config.DEFAULT_DEV_HUB_USERNAME : config_1.Config.DEFAULT_USERNAME;
|
|
665
|
+
const configInfo = orgForUser.configAggregator.getInfo(orgType);
|
|
666
|
+
const needsConfigUpdate = (configInfo.isGlobal() || configInfo.isLocal()) &&
|
|
667
|
+
(configInfo.value === username || aliasKeys.includes(configInfo.value));
|
|
668
|
+
return [
|
|
669
|
+
orgForUser.removeAuth(),
|
|
670
|
+
needsConfigUpdate ? config_1.Config.update(configInfo.isGlobal(), orgType, undefined) : undefined,
|
|
671
|
+
].filter(Boolean);
|
|
672
|
+
}));
|
|
673
|
+
await aliases.write();
|
|
676
674
|
}
|
|
677
675
|
/**
|
|
678
676
|
* Remove an associate sandbox config.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { Optional } from '@salesforce/ts-types';
|
|
2
2
|
import { Logger } from './logger';
|
|
3
3
|
import { ScratchOrgInfo } from './scratchOrgInfoApi';
|
|
4
|
-
export declare const checkScratchOrgInfoForErrors: (orgInfo: ScratchOrgInfo
|
|
4
|
+
export declare const checkScratchOrgInfoForErrors: (orgInfo: Optional<ScratchOrgInfo>, hubUsername: Optional<string>, logger: Logger) => ScratchOrgInfo;
|
|
@@ -29,6 +29,9 @@ const optionalErrorCodeMessage = (errorCode, args) => {
|
|
|
29
29
|
}
|
|
30
30
|
};
|
|
31
31
|
const checkScratchOrgInfoForErrors = (orgInfo, hubUsername, logger) => {
|
|
32
|
+
if (!orgInfo) {
|
|
33
|
+
throw new sfdxError_1.SfdxError('No scratch org info found.', 'ScratchOrgInfoNotFound');
|
|
34
|
+
}
|
|
32
35
|
if (orgInfo.Status === 'Active') {
|
|
33
36
|
return orgInfo;
|
|
34
37
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Optional } from '@salesforce/ts-types';
|
|
2
2
|
import { Duration } from '@salesforce/kit';
|
|
3
3
|
import { RecordResult } from 'jsforce';
|
|
4
|
-
import { retry } from 'ts-retry-promise';
|
|
5
4
|
import { Org } from './org';
|
|
6
5
|
import { AuthInfo } from './authInfo';
|
|
7
6
|
import SettingsGenerator, { ObjectSetting } from './scratchOrgSettingsGenerator';
|
package/lib/scratchOrgInfoApi.js
CHANGED
|
@@ -18,6 +18,7 @@ const authInfo_1 = require("./authInfo");
|
|
|
18
18
|
const messages_1 = require("./messages");
|
|
19
19
|
const sfdxError_1 = require("./sfdxError");
|
|
20
20
|
const sfdcUrl_1 = require("./util/sfdcUrl");
|
|
21
|
+
const pollingClient_1 = require("./status/pollingClient");
|
|
21
22
|
const myDomainResolver_1 = require("./status/myDomainResolver");
|
|
22
23
|
const scratchOrgErrorCodes_1 = require("./scratchOrgErrorCodes");
|
|
23
24
|
messages_1.Messages.importMessagesDirectory(__dirname);
|
|
@@ -251,30 +252,53 @@ const pollForScratchOrgInfo = async (hubOrg, scratchOrgInfoId,
|
|
|
251
252
|
timeout = kit_1.Duration.minutes(15)) => {
|
|
252
253
|
const logger = await logger_1.Logger.child('scratchOrgInfoApi-pollForScratchOrgInfo');
|
|
253
254
|
logger.debug(`PollingTimeout in minutes: ${timeout.minutes}`);
|
|
254
|
-
const
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
255
|
+
const pollingOptions = {
|
|
256
|
+
async poll() {
|
|
257
|
+
try {
|
|
258
|
+
const resultInProgress = await hubOrg
|
|
259
|
+
.getConnection()
|
|
260
|
+
.sobject('ScratchOrgInfo')
|
|
261
|
+
.retrieve(scratchOrgInfoId);
|
|
262
|
+
logger.debug(`polling client result: ${JSON.stringify(resultInProgress, null, 4)}`);
|
|
263
|
+
// Once it's "done" we can return it
|
|
264
|
+
if (resultInProgress.Status === 'Active' || resultInProgress.Status === 'Error') {
|
|
265
|
+
return {
|
|
266
|
+
completed: true,
|
|
267
|
+
payload: resultInProgress,
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
logger.debug(`Scratch org status is ${resultInProgress.Status}`);
|
|
271
|
+
return {
|
|
272
|
+
completed: false,
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
catch (error) {
|
|
276
|
+
logger.debug(`An error occurred trying to retrieve scratchOrgInfo for ${scratchOrgInfoId}`);
|
|
277
|
+
logger.debug(`Error: ${error.message}`);
|
|
278
|
+
logger.debug('Re-trying deploy check again....');
|
|
279
|
+
return {
|
|
280
|
+
completed: false,
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
},
|
|
284
|
+
timeout,
|
|
285
|
+
frequency: kit_1.Duration.seconds(1),
|
|
286
|
+
timeoutErrorName: 'ScratchOrgInfoTimeoutError',
|
|
287
|
+
};
|
|
288
|
+
const client = await pollingClient_1.PollingClient.create(pollingOptions);
|
|
289
|
+
try {
|
|
290
|
+
const resultInProgress = await client.subscribe();
|
|
291
|
+
return scratchOrgErrorCodes_1.checkScratchOrgInfoForErrors(resultInProgress, hubOrg.getUsername(), logger);
|
|
292
|
+
}
|
|
293
|
+
catch (error) {
|
|
294
|
+
const err = error;
|
|
295
|
+
if (err.message) {
|
|
296
|
+
throw sfdxError_1.SfdxError.wrap(err);
|
|
263
297
|
}
|
|
264
|
-
// all other statuses, OR lack of status (e.g. network errors) will cause a retry
|
|
265
|
-
throw new sfdxError_1.SfdxError(`Scratch org status is ${resultInProgress.Status}`);
|
|
266
|
-
}, {
|
|
267
|
-
retries: 'INFINITELY',
|
|
268
|
-
timeout: timeout.milliseconds,
|
|
269
|
-
delay: kit_1.Duration.seconds(2).milliseconds,
|
|
270
|
-
backoff: 'LINEAR',
|
|
271
|
-
maxBackOff: kit_1.Duration.seconds(30).milliseconds,
|
|
272
|
-
}).catch(() => {
|
|
273
298
|
throw new sfdxError_1.SfdxError(`The scratch org did not complete within ${timeout.minutes} minutes`, 'orgCreationTimeout', [
|
|
274
299
|
'Try your force:org:create command again with a longer --wait value',
|
|
275
300
|
]);
|
|
276
|
-
}
|
|
277
|
-
return scratchOrgErrorCodes_1.checkScratchOrgInfoForErrors(response, hubOrg.getUsername(), logger);
|
|
301
|
+
}
|
|
278
302
|
};
|
|
279
303
|
exports.pollForScratchOrgInfo = pollForScratchOrgInfo;
|
|
280
304
|
/**
|
|
@@ -101,7 +101,7 @@ class SettingsGenerator {
|
|
|
101
101
|
timeoutErrorName: 'DeployingSettingsTimeoutError',
|
|
102
102
|
};
|
|
103
103
|
const client = await pollingClient_1.PollingClient.create(pollingOptions);
|
|
104
|
-
const status =
|
|
104
|
+
const status = await client.subscribe();
|
|
105
105
|
if (status !== RequestStatus.Succeeded) {
|
|
106
106
|
const componentFailures = ts_types_1.ensureObject(result.details).componentFailures;
|
|
107
107
|
const failures = (Array.isArray(componentFailures) ? componentFailures : [componentFailures])
|
|
@@ -38,7 +38,7 @@ export declare class PollingClient extends AsyncOptionalCreatable<PollingClient.
|
|
|
38
38
|
* Returns a promise to call the specified polling function using the interval and timeout specified
|
|
39
39
|
* in the polling options.
|
|
40
40
|
*/
|
|
41
|
-
subscribe(): Promise<
|
|
41
|
+
subscribe<T = AnyJson>(): Promise<T | undefined>;
|
|
42
42
|
}
|
|
43
43
|
export declare namespace PollingClient {
|
|
44
44
|
/**
|
|
@@ -12,6 +12,7 @@ const ts_types_1 = require("@salesforce/ts-types");
|
|
|
12
12
|
const ts_retry_promise_1 = require("ts-retry-promise");
|
|
13
13
|
const logger_1 = require("../logger");
|
|
14
14
|
const sfdxError_1 = require("../sfdxError");
|
|
15
|
+
const lifecycleEvents_1 = require("../lifecycleEvents");
|
|
15
16
|
/**
|
|
16
17
|
* This is a polling client that can be used to poll the status of long running tasks. It can be used as a replacement
|
|
17
18
|
* for Streaming when streaming topics are not available or when streaming handshakes are failing. Why wouldn't you
|
|
@@ -51,6 +52,7 @@ class PollingClient extends kit_1.AsyncOptionalCreatable {
|
|
|
51
52
|
* Returns a promise to call the specified polling function using the interval and timeout specified
|
|
52
53
|
* in the polling options.
|
|
53
54
|
*/
|
|
55
|
+
// TODO v3.0 remove undefined as this method ensures that the payload is always returned
|
|
54
56
|
async subscribe() {
|
|
55
57
|
var _a;
|
|
56
58
|
let errorInPollingFunction; // keep this around for returning in the catch block
|
|
@@ -60,11 +62,18 @@ class PollingClient extends kit_1.AsyncOptionalCreatable {
|
|
|
60
62
|
result = await this.options.poll();
|
|
61
63
|
}
|
|
62
64
|
catch (error) {
|
|
63
|
-
errorInPollingFunction = error;
|
|
65
|
+
const err = (errorInPollingFunction = error);
|
|
66
|
+
if (['ETIMEDOUT', 'ENOTFOUND', 'ECONNRESET', 'socket hang up'].some((retryableNetworkError) => err.message.includes(retryableNetworkError))) {
|
|
67
|
+
this.logger.debug('Network error on the request', err);
|
|
68
|
+
await lifecycleEvents_1.Lifecycle.getInstance().emitWarning('Network error occurred. Continuing to poll.');
|
|
69
|
+
throw sfdxError_1.SfdxError.wrap(err);
|
|
70
|
+
}
|
|
64
71
|
// there was an actual error thrown, so we don't want to keep retrying
|
|
65
|
-
throw new ts_retry_promise_1.NotRetryableError(
|
|
72
|
+
throw new ts_retry_promise_1.NotRetryableError(err.name);
|
|
66
73
|
}
|
|
67
74
|
if (result.completed) {
|
|
75
|
+
// TODO v3.0: payload should be of type T always so that
|
|
76
|
+
// consumers get the same type in return.
|
|
68
77
|
return result.payload;
|
|
69
78
|
}
|
|
70
79
|
throw new Error('Operation did not complete. Retrying...'); // triggers a retry
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.36.0",
|
|
4
4
|
"description": "Core libraries to interact with SFDX projects, orgs, and APIs.",
|
|
5
5
|
"main": "lib/exported",
|
|
6
6
|
"types": "lib/exported.d.ts",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"@salesforce/schemas": "^1.0.1",
|
|
40
40
|
"@salesforce/ts-types": "^1.5.20",
|
|
41
41
|
"@types/graceful-fs": "^4.1.5",
|
|
42
|
-
"@types/jsforce": "^1.9.
|
|
42
|
+
"@types/jsforce": "^1.9.41",
|
|
43
43
|
"@types/mkdirp": "^1.0.1",
|
|
44
44
|
"archiver": "^5.3.0",
|
|
45
45
|
"debug": "^3.1.0",
|