diff --git a/package.json b/package.json index 6874424d..e5d0998a 100644 --- a/package.json +++ b/package.json @@ -50,9 +50,9 @@ }, "dependencies": { "@oclif/core": "^4.0.18", - "@salesforce/core": "^8.4.0", + "@salesforce/core": "^8.5.4", "@salesforce/kit": "^3.2.1", - "@salesforce/source-deploy-retrieve": "^12.5.1", + "@salesforce/source-deploy-retrieve": "^12.6.0", "@salesforce/ts-types": "^2.0.12", "fast-xml-parser": "^4.4.1", "graceful-fs": "^4.2.11", diff --git a/src/shared/remoteSourceTrackingService.ts b/src/shared/remoteSourceTrackingService.ts index 4334d8d3..9931a5f0 100644 --- a/src/shared/remoteSourceTrackingService.ts +++ b/src/shared/remoteSourceTrackingService.ts @@ -9,8 +9,8 @@ import path from 'node:path'; import fs from 'node:fs'; import { EOL } from 'node:os'; import { retryDecorator, NotRetryableError } from 'ts-retry-promise'; -import { Logger, Org, Messages, Lifecycle, SfError, Connection, lockInit } from '@salesforce/core'; -import { env, Duration, parseJsonMap } from '@salesforce/kit'; +import { envVars as env, Logger, Org, Messages, Lifecycle, SfError, Connection, lockInit } from '@salesforce/core'; +import { Duration, parseJsonMap } from '@salesforce/kit'; import { isString } from '@salesforce/ts-types'; import { ChangeResult, @@ -40,7 +40,7 @@ const FILENAME = 'maxRevision.json'; */ const POLLING_DELAY_MS = 1000; const CONSECUTIVE_EMPTY_POLLING_RESULT_LIMIT = - (env.getNumber('SFDX_SOURCE_MEMBER_POLLING_TIMEOUT') ?? 120) / Duration.milliseconds(POLLING_DELAY_MS).seconds; + (env.getNumber('SF_SOURCE_MEMBER_POLLING_TIMEOUT') ?? 120) / Duration.milliseconds(POLLING_DELAY_MS).seconds; /** Options for RemoteSourceTrackingService.getInstance */ export type RemoteSourceTrackingServiceOptions = { @@ -237,8 +237,8 @@ export class RemoteSourceTrackingService { * @param pollingTimeout maximum amount of time in seconds to poll for SourceMembers */ public async pollForSourceTracking(expectedMembers: RemoteSyncInput[]): Promise { - if (env.getBoolean('SFDX_DISABLE_SOURCE_MEMBER_POLLING', false)) { - this.logger.warn('Not polling for SourceMembers since SFDX_DISABLE_SOURCE_MEMBER_POLLING = true.'); + if (env.getBoolean('SF_DISABLE_SOURCE_MEMBER_POLLING')) { + this.logger.warn('Not polling for SourceMembers since SF_DISABLE_SOURCE_MEMBER_POLLING = true.'); return; } @@ -572,7 +572,7 @@ const readFileContents = async (filePath: string): Promise (memberCount: number): Duration => { - const overriddenTimeout = env.getNumber('SFDX_SOURCE_MEMBER_POLLING_TIMEOUT', 0); + const overriddenTimeout = env.getNumber('SF_SOURCE_MEMBER_POLLING_TIMEOUT', 0); if (overriddenTimeout > 0) { logger.debug(`Overriding SourceMember polling timeout to ${overriddenTimeout}`); return Duration.seconds(overriddenTimeout); diff --git a/test/unit/remoteSourceTracking.test.ts b/test/unit/remoteSourceTracking.test.ts index 05b08256..12ce75e7 100644 --- a/test/unit/remoteSourceTracking.test.ts +++ b/test/unit/remoteSourceTracking.test.ts @@ -11,9 +11,7 @@ import { writeFile, mkdir, readFile } from 'node:fs/promises'; import { existsSync } from 'node:fs'; import { sep, dirname } from 'node:path'; import { MockTestOrgData, instantiateContext, stubContext, restoreContext } from '@salesforce/core/testSetup'; -import { Logger, Messages, Org } from '@salesforce/core'; -// eslint-disable-next-line no-restricted-imports -import * as kit from '@salesforce/kit'; +import { EnvVars, envVars, Logger, Messages, Org } from '@salesforce/core'; import { expect } from 'chai'; import { ComponentStatus } from '@salesforce/source-deploy-retrieve'; import { RemoteSourceTrackingService, calculateTimeout, Contents } from '../../src/shared/remoteSourceTrackingService'; @@ -42,6 +40,13 @@ const getMemberRevisionEntries = (revision: number, synced = false): { [key: str return sourceMemberEntries; }; +const reResolveEnvVars = (): void => { + /* eslint-disable @typescript-eslint/no-unsafe-call */ + // @ts-ignore to force a re-resolve + envVars.resolve(); + /* eslint-enable @typescript-eslint/no-unsafe-call */ +}; + describe('remoteSourceTrackingService', () => { const username = 'foo@bar.com'; let orgId: string; @@ -408,6 +413,13 @@ describe('remoteSourceTrackingService', () => { state: ComponentStatus.Changed, })); + afterEach(() => { + envVars.unset('SFDX_DISABLE_SOURCE_MEMBER_POLLING'); + envVars.unset('SF_DISABLE_SOURCE_MEMBER_POLLING'); + envVars.unset('SFDX_SOURCE_MEMBER_POLLING_TIMEOUT'); + envVars.unset('SF_SOURCE_MEMBER_POLLING_TIMEOUT'); + }); + it('should sync SourceMembers when query results match', async () => { // @ts-ignore const queryStub = $$.SANDBOX.stub(remoteSourceTrackingService, 'querySourceMembersFrom'); @@ -469,7 +481,23 @@ describe('remoteSourceTrackingService', () => { }); }); it('should not poll when SFDX_DISABLE_SOURCE_MEMBER_POLLING=true', async () => { - const getBooleanStub = $$.SANDBOX.stub(kit.env, 'getBoolean').callsFake(() => true); + envVars.setString('SFDX_DISABLE_SOURCE_MEMBER_POLLING', 'true'); + + reResolveEnvVars(); + const getBooleanSpy = $$.SANDBOX.spy(EnvVars.prototype, 'getBoolean'); + + // @ts-ignore + const trackSpy = $$.SANDBOX.stub(remoteSourceTrackingService, 'trackSourceMembers'); + + // @ts-ignore + await remoteSourceTrackingService.pollForSourceTracking(memberNames, 2); + expect(trackSpy.called).to.equal(false); + expect(getBooleanSpy.calledOnce).to.equal(true); + }); + it('should not poll when SF_DISABLE_SOURCE_MEMBER_POLLING=true', async () => { + envVars.setString('SF_DISABLE_SOURCE_MEMBER_POLLING', 'true'); + reResolveEnvVars(); + const getBooleanSpy = $$.SANDBOX.spy(EnvVars.prototype, 'getBoolean'); // @ts-ignore const trackSpy = $$.SANDBOX.stub(remoteSourceTrackingService, 'trackSourceMembers'); @@ -477,7 +505,7 @@ describe('remoteSourceTrackingService', () => { // @ts-ignore await remoteSourceTrackingService.pollForSourceTracking(memberNames, 2); expect(trackSpy.called).to.equal(false); - expect(getBooleanStub.calledOnce).to.equal(true); + expect(getBooleanSpy.calledOnce).to.equal(true); }); describe('timeout handling', () => { @@ -511,8 +539,26 @@ describe('remoteSourceTrackingService', () => { }).timeout(10_000); it('should stop if SFDX_SOURCE_MEMBER_POLLING_TIMEOUT is exceeded', async () => { + envVars.setString('SFDX_SOURCE_MEMBER_POLLING_TIMEOUT', '3'); + reResolveEnvVars(); // @ts-ignore - $$.SANDBOX.stub(kit.env, 'getString').callsFake(() => '3'); + const queryStub = $$.SANDBOX.stub(remoteSourceTrackingService, 'querySourceMembersFrom').resolves([]); + + // @ts-ignore + const trackSpy = $$.SANDBOX.stub(remoteSourceTrackingService, 'trackSourceMembers'); + + // @ts-ignore + await remoteSourceTrackingService.pollForSourceTracking(memberNames); + expect(trackSpy.called).to.equal(true); + + expect(warns.size).to.be.greaterThan(0); + const expectedMsg = 'Polling for 3 SourceMembers timed out after 3 attempts'; + expect(Array.from(warns).some((w) => w.includes(expectedMsg))).to.equal(true); + expect(queryStub.called).to.equal(true); + }); + it('should stop if SF_SOURCE_MEMBER_POLLING_TIMEOUT is exceeded', async () => { + envVars.setString('SF_SOURCE_MEMBER_POLLING_TIMEOUT', '3'); + reResolveEnvVars(); // @ts-ignore const queryStub = $$.SANDBOX.stub(remoteSourceTrackingService, 'querySourceMembersFrom').resolves([]); @@ -587,7 +633,8 @@ describe('calculateTimeout', () => { const logger = new Logger({ useMemoryLogger: true, name: 'test' }).getRawLogger(); const functionUnderTest = calculateTimeout(logger); afterEach(() => { - delete process.env.SFDX_SOURCE_MEMBER_POLLING_TIMEOUT; + envVars.unset('SFDX_SOURCE_MEMBER_POLLING_TIMEOUT'); + envVars.unset('SF_SOURCE_MEMBER_POLLING_TIMEOUT'); }); it('0 members => 5 sec', () => { expect(functionUnderTest(0).seconds).to.equal(5); @@ -596,11 +643,13 @@ describe('calculateTimeout', () => { expect(functionUnderTest(10_000).seconds).to.equal(505); }); it('override 60 in env', () => { - process.env.SFDX_SOURCE_MEMBER_POLLING_TIMEOUT = '60'; + envVars.setString('SFDX_SOURCE_MEMBER_POLLING_TIMEOUT', '60'); + reResolveEnvVars(); expect(functionUnderTest(10_000).seconds).to.equal(60); }); it('override 0 in env has no effect', () => { - process.env.SFDX_SOURCE_MEMBER_POLLING_TIMEOUT = '0'; + envVars.setString('SFDX_SOURCE_MEMBER_POLLING_TIMEOUT', '0'); + reResolveEnvVars(); expect(functionUnderTest(10_000).seconds).to.equal(505); }); }); diff --git a/yarn.lock b/yarn.lock index 26ea984a..02a0e755 100644 --- a/yarn.lock +++ b/yarn.lock @@ -463,7 +463,7 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" -"@jsforce/jsforce-node@^3.4.0": +"@jsforce/jsforce-node@^3.4.1": version "3.4.1" resolved "https://registry.yarnpkg.com/@jsforce/jsforce-node/-/jsforce-node-3.4.1.tgz#36f5cba775b395eeedba676a78eafe447c3f4b28" integrity sha512-PsBKfglH0/8W/Srr4LsxEFsVmjmZjEj/T4XLGpbBoK8yVObwbiMk4VqwA6XwiA6SHqnEqqQbHZxk2rr7dZC+4A== @@ -546,13 +546,13 @@ strip-ansi "6.0.1" ts-retry-promise "^0.8.1" -"@salesforce/core@^8.3.0", "@salesforce/core@^8.4.0": - version "8.4.0" - resolved "https://registry.yarnpkg.com/@salesforce/core/-/core-8.4.0.tgz#d2ddfe07994c42b1e917e581e9cf47ad27b97a93" - integrity sha512-P+n0+Sp+v6voLTShW2E5sdF7gCUxEXJjNcc9Jtto0ZMyQesmQJ6WGpWmAuRoi+BVYc8OPSlEffndaYDAo/u73g== +"@salesforce/core@^8.3.0", "@salesforce/core@^8.5.2", "@salesforce/core@^8.5.4": + version "8.5.4" + resolved "https://registry.yarnpkg.com/@salesforce/core/-/core-8.5.4.tgz#1cdd669462d2c2859b72135d1138a1b790b1fbcc" + integrity sha512-dO8tzFxq811qNPeKPPO2OA2KPYW5rO0YRinW/+7zmRJW3EtNpe93dsQVGwBSAAYrSbYeBwiKdliNqNTN7tKJ0A== dependencies: - "@jsforce/jsforce-node" "^3.4.0" - "@salesforce/kit" "^3.1.6" + "@jsforce/jsforce-node" "^3.4.1" + "@salesforce/kit" "^3.2.2" "@salesforce/schemas" "^1.9.0" "@salesforce/ts-types" "^2.0.10" ajv "^8.17.1" @@ -607,10 +607,10 @@ typescript "^5.5.4" wireit "^0.14.5" -"@salesforce/kit@^3.1.6", "@salesforce/kit@^3.2.1": - version "3.2.1" - resolved "https://registry.yarnpkg.com/@salesforce/kit/-/kit-3.2.1.tgz#3de2c9ff52710a169fc887716d97c00d26065c56" - integrity sha512-LrZH2F06XPLUTMXC3av6A0VDAJykUqRtYB6tTjAKzwS1gCnp6BEn6VyjZNg0Fg/Kfp6OTrMxiIgbUFsNehEV7A== +"@salesforce/kit@^3.2.1", "@salesforce/kit@^3.2.2": + version "3.2.2" + resolved "https://registry.yarnpkg.com/@salesforce/kit/-/kit-3.2.2.tgz#2a0db472116a416cb12b510d546cb35a582d619a" + integrity sha512-Qh+Jx65LKR3BlH+bxNBbvI4+/+/igAJ9x2iEDM3tHb3B2JCEnssPP0lw+K/zWHsdtk+OorBiKpHaC6RrjW+9fw== dependencies: "@salesforce/ts-types" "^2.0.12" @@ -624,19 +624,20 @@ resolved "https://registry.yarnpkg.com/@salesforce/schemas/-/schemas-1.9.0.tgz#ba477a112653a20b4edcf989c61c57bdff9aa3ca" integrity sha512-LiN37zG5ODT6z70sL1fxF7BQwtCX9JOWofSU8iliSNIM+WDEeinnoFtVqPInRSNt8I0RiJxIKCrqstsmQRBNvA== -"@salesforce/source-deploy-retrieve@^12.5.1": - version "12.5.1" - resolved "https://registry.yarnpkg.com/@salesforce/source-deploy-retrieve/-/source-deploy-retrieve-12.5.1.tgz#55e915201b2c9320b9662b2c8500a191c8770ecf" - integrity sha512-jakBWFSIb8oZlUAf0QKHXaeFA/KuTQZwaKZVevdwaiuy43lJHzVVrSRfcNv/kjXxmg0oq5TAI8vUo2CC5Hq04A== +"@salesforce/source-deploy-retrieve@^12.6.0": + version "12.6.2" + resolved "https://registry.yarnpkg.com/@salesforce/source-deploy-retrieve/-/source-deploy-retrieve-12.6.2.tgz#eb9ab120621c80a404b9ec45a2b102f3f2befbff" + integrity sha512-ucEt/CyzL4ovMc2cYREk4meQzKe6/FlY/D09yLmOQ118Oec680ehEhJ1kGRE/I7HTzfgQP3Fy2GzhQX1bOYC5Q== dependencies: - "@salesforce/core" "^8.4.0" - "@salesforce/kit" "^3.2.1" + "@salesforce/core" "^8.5.2" + "@salesforce/kit" "^3.2.2" "@salesforce/ts-types" "^2.0.12" fast-levenshtein "^3.0.0" fast-xml-parser "^4.4.1" got "^11.8.6" graceful-fs "^4.2.11" ignore "^5.3.2" + isbinaryfile "^5.0.2" jszip "^3.10.1" mime "2.6.0" minimatch "^9.0.5" @@ -1339,20 +1340,13 @@ brace-expansion@^4.0.0: dependencies: balanced-match "^3.0.0" -braces@^3.0.3: +braces@^3.0.3, braces@~3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== dependencies: fill-range "^7.1.1" -braces@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== - dependencies: - fill-range "^7.0.1" - browser-stdout@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" @@ -2499,13 +2493,6 @@ filelist@^1.0.4: dependencies: minimatch "^5.0.1" -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== - dependencies: - to-regex-range "^5.0.1" - fill-range@^7.1.1: version "7.1.1" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" @@ -3307,6 +3294,11 @@ isarray@~1.0.0: resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== +isbinaryfile@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-5.0.2.tgz#fe6e4dfe2e34e947ffa240c113444876ba393ae0" + integrity sha512-GvcjojwonMjWbTkfMpnVHVqXW/wKMYDfEpY94/8zy8HFMOqb/VL6oeONq9v87q4ttVlaTLnGXnJD4B5B1OTGIg== + isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -5146,16 +5138,7 @@ srcset@^5.0.0: resolved "https://registry.yarnpkg.com/srcset/-/srcset-5.0.0.tgz#9df6c3961b5b44a02532ce6ae4544832609e2e3f" integrity sha512-SqEZaAEhe0A6ETEa9O1IhSPC7MdvehZtCnTR0AftXk3QhY2UNgb+NApFOUPZILXk/YTDfFxMTNJOBpzrJsEdIA== -"string-width-cjs@npm:string-width@^4.2.0": - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -5214,14 +5197,7 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-ansi@6.0.1, strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@6.0.1, strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -5721,7 +5697,7 @@ workerpool@^6.5.1: resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.5.1.tgz#060f73b39d0caf97c6db64da004cd01b4c099544" integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -5739,15 +5715,6 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"