From 73228f3c56640d945cd8fa191a3c2b9c6bcd6b01 Mon Sep 17 00:00:00 2001 From: Shane McLaughlin Date: Thu, 23 May 2024 15:11:07 -0500 Subject: [PATCH] fix: quick-action-definition (#590) * refactor: simplify logger and maxRevision * fix: quickActionDefinition isn't a real mdtype * refactor: use newer error * test: update for logger refactor * chore: bump deps for xnuts * Update remoteSourceTrackingService.ts link to WI assigned to Platform Actions * chore: bump deps --------- Co-authored-by: Cristian Dominguez <6853656+cristiand391@users.noreply.github.com> --- package.json | 6 +- src/shared/remoteSourceTrackingService.ts | 83 +++++++++++------------ test/unit/remoteSourceTracking.test.ts | 2 +- yarn.lock | 67 ++++++------------ 4 files changed, 65 insertions(+), 93 deletions(-) diff --git a/package.json b/package.json index 5ec49e2e..05537e29 100644 --- a/package.json +++ b/package.json @@ -50,9 +50,9 @@ }, "dependencies": { "@oclif/core": "^3.26.6", - "@salesforce/core": "^7.3.8", + "@salesforce/core": "^7.3.9", "@salesforce/kit": "^3.1.1", - "@salesforce/source-deploy-retrieve": "^11.4.4", + "@salesforce/source-deploy-retrieve": "^11.6.1", "@salesforce/ts-types": "^2.0.9", "fast-xml-parser": "^4.3.6", "graceful-fs": "^4.2.11", @@ -63,7 +63,7 @@ "@salesforce/cli-plugins-testkit": "^5.3.4", "@salesforce/dev-scripts": "^9.1.2", "@types/graceful-fs": "^4.1.9", - "eslint-plugin-sf-plugin": "^1.18.3", + "eslint-plugin-sf-plugin": "^1.18.4", "ts-node": "^10.9.2", "ts-patch": "^3.1.2", "typescript": "^5.4.5" diff --git a/src/shared/remoteSourceTrackingService.ts b/src/shared/remoteSourceTrackingService.ts index 588cdd77..2a080e23 100644 --- a/src/shared/remoteSourceTrackingService.ts +++ b/src/shared/remoteSourceTrackingService.ts @@ -30,6 +30,7 @@ export type Contents = { sourceMembers: Record; }; type MemberRevisionMapEntry = [string, MemberRevision]; +type PinoLogger = ReturnType<(typeof Logger)['getRawRootLogger']>; const FILENAME = 'maxRevision.json'; @@ -88,7 +89,7 @@ export class RemoteSourceTrackingService { private static instanceMap = new Map(); public readonly filePath: string; - private logger!: Logger; + private logger!: PinoLogger; private serverMaxRevisionCounter = 0; private sourceMembers = new Map(); @@ -146,10 +147,8 @@ export class RemoteSourceTrackingService { if (elements.length === 0) { return; } - const quiet = elements.length > 100; - if (quiet) { - this.logger.debug(`Syncing ${elements.length} Revisions by key`); - } + const quietLogger = elements.length > 100 ? this.logger.silent : this.logger.debug; + quietLogger(`Syncing ${elements.length} Revisions by key`); // this can be super-repetitive on a large ExperienceBundle where there is an element for each file but only one Revision for the entire bundle // any item in an aura/LWC bundle needs to represent the top (bundle) level and the file itself @@ -159,11 +158,9 @@ export class RemoteSourceTrackingService { if (!revision) { this.logger.warn(`found no matching revision for ${metadataKey}`); } else if (doesNotMatchServer(revision)) { - if (!quiet) { - this.logger.debug( - `Syncing ${metadataKey} revision from ${revision.lastRetrievedFromServer} to ${revision.serverRevisionCounter}` - ); - } + quietLogger( + `Syncing ${metadataKey} revision from ${revision.lastRetrievedFromServer} to ${revision.serverRevisionCounter}` + ); this.setMemberRevision(metadataKey, { ...revision, lastRetrievedFromServer: revision.serverRevisionCounter }); } }); @@ -377,13 +374,17 @@ ${formatSourceMemberWarnings(outstandingSourceMembers)}` if (sourceMembers.length === 0) { return; } - const quiet = sourceMembers.length > 100; - if (quiet) { - this.logger.debug(`Upserting ${sourceMembers.length} SourceMembers to maxRevision.json`); - } + const quietLogger = sourceMembers.length > 100 ? this.logger.silent : this.logger.debug; + quietLogger(`Upserting ${sourceMembers.length} SourceMembers to maxRevision.json`); - let serverMaxRevisionCounter = this.serverMaxRevisionCounter; - sourceMembers.forEach((change) => { + // Update the serverMaxRevisionCounter to the highest RevisionCounter + this.serverMaxRevisionCounter = Math.max( + this.serverMaxRevisionCounter, + ...sourceMembers.map((m) => m.RevisionCounter) + ); + this.logger.debug(`Updating serverMaxRevisionCounter to ${this.serverMaxRevisionCounter}`); + + sourceMembers.map((change) => { // try accessing the sourceMembers object at the index of the change's name // if it exists, we'll update the fields - if it doesn't, we'll create and insert it const key = getMetadataKey(change.MemberType, change.MemberName); @@ -395,18 +396,12 @@ ${formatSourceMemberWarnings(outstandingSourceMembers)}` }; if (sourceMember.lastRetrievedFromServer) { // We are already tracking this element so we'll update it - if (!quiet) { - this.logger.debug( - `Updating ${key} to RevisionCounter: ${change.RevisionCounter}${sync ? ' and syncing' : ''}` - ); - } + quietLogger(`Updating ${key} to RevisionCounter: ${change.RevisionCounter}${sync ? ' and syncing' : ''}`); sourceMember.serverRevisionCounter = change.RevisionCounter; sourceMember.isNameObsolete = change.IsNameObsolete; - } else if (!quiet) { + } else { // We are not yet tracking it so we'll insert a new record - this.logger.debug( - `Inserting ${key} with RevisionCounter: ${change.RevisionCounter}${sync ? ' and syncing' : ''}` - ); + quietLogger(`Inserting ${key} with RevisionCounter: ${change.RevisionCounter}${sync ? ' and syncing' : ''}`); } // If we are syncing changes then we need to update the lastRetrievedFromServer field to @@ -414,16 +409,10 @@ ${formatSourceMemberWarnings(outstandingSourceMembers)}` if (sync) { sourceMember.lastRetrievedFromServer = change.RevisionCounter; } - // Keep track of the highest RevisionCounter for setting the serverMaxRevisionCounter - if (change.RevisionCounter > serverMaxRevisionCounter) { - serverMaxRevisionCounter = change.RevisionCounter; - } + // Update the state with the latest SourceMember data this.setMemberRevision(key, sourceMember); }); - // Update the serverMaxRevisionCounter to the highest RevisionCounter - this.serverMaxRevisionCounter = serverMaxRevisionCounter; - this.logger.debug(`Updating serverMaxRevisionCounter to ${serverMaxRevisionCounter}`); await this.write(); } @@ -435,7 +424,7 @@ ${formatSourceMemberWarnings(outstandingSourceMembers)}` const messages = Messages.loadMessages('@salesforce/source-tracking', 'source'); throw new SfError(messages.getMessage('NonSourceTrackedOrgError'), 'NonSourceTrackedOrgError'); } - this.logger = await Logger.child(this.constructor.name); + this.logger = Logger.getRawRootLogger().child({ name: this.constructor.name }); if (fs.existsSync(this.filePath)) { // read the file contents and turn it into the map const rawContents = await readFileContents(this.filePath); @@ -486,9 +475,7 @@ ${formatSourceMemberWarnings(outstandingSourceMembers)}` // because `serverMaxRevisionCounter` is always updated, we need to select > to catch the most recent change const query = `SELECT MemberType, MemberName, IsNameObsolete, RevisionCounter FROM SourceMember WHERE RevisionCounter > ${rev}`; - if (!quiet) { - this.logger.debug(`Query: ${query}`); - } + this.logger[quiet ? 'silent' : 'debug'](`Query: ${query}`); const queryResult = await queryFn(this.org.getConnection(), query); this.queryCache.set(rev, queryResult); @@ -536,15 +523,15 @@ const revisionToRemoteChangeElement = ([memberKey, memberRevision]: MemberRevisi * iterate SourceMember keys and compare their decoded value with the decoded key. * if there's a match, return the matching decoded key, otherwise, return the original key */ -function getDecodedKeyIfSourceMembersHas({ +const getDecodedKeyIfSourceMembersHas = ({ key, sourceMembers, logger, }: { sourceMembers: Map; key: string; - logger: Logger; -}): string { + logger: PinoLogger; +}): string => { try { const originalKeyDecoded = decodeURIComponent(key); const match = Array.from(sourceMembers.keys()).find( @@ -560,7 +547,7 @@ function getDecodedKeyIfSourceMembersHas({ logger.debug(`Could not decode metadata key: ${key} due to: ${errMsg}`); } return key; -} +}; const getFilePath = (orgId: string): string => path.join('.sf', 'orgs', orgId, FILENAME); @@ -579,7 +566,7 @@ const readFileContents = async (filePath: string): Promise + (logger: PinoLogger) => (memberCount: number): Duration => { const overriddenTimeout = env.getNumber('SFDX_SOURCE_MEMBER_POLLING_TIMEOUT', 0); if (overriddenTimeout > 0) { @@ -603,9 +590,11 @@ export const querySourceMembersTo = async (conn: Connection, toRevision: number) const queryFn = async (conn: Connection, query: string): Promise => { try { - return (await conn.tooling.query(query, { autoFetch: true, maxFetch: 50_000 })).records; + return (await conn.tooling.query(query, { autoFetch: true, maxFetch: 50_000 })).records.map( + sourceMemberCorrections + ); } catch (error) { - throw error instanceof Error ? SfError.wrap(error) : error; + throw SfError.wrap(error); } }; @@ -625,3 +614,11 @@ const revisionDoesNotMatch = ([, member]: MemberRevisionMapEntry): boolean => do const doesNotMatchServer = (member: MemberRevision): boolean => member.serverRevisionCounter !== member.lastRetrievedFromServer; + +/** A series of workarounds for server-side bugs. Each bug should be filed against a team, with a WI, so we know when these are fixed and can be removed */ +const sourceMemberCorrections = (sourceMember: SourceMember): SourceMember => { + if (sourceMember.MemberType === 'QuickActionDefinition') { + return { ...sourceMember, MemberType: 'QuickAction' }; // W-15837125 + } + return sourceMember; +}; diff --git a/test/unit/remoteSourceTracking.test.ts b/test/unit/remoteSourceTracking.test.ts index e7181c1d..05b08256 100644 --- a/test/unit/remoteSourceTracking.test.ts +++ b/test/unit/remoteSourceTracking.test.ts @@ -584,7 +584,7 @@ describe('remoteSourceTrackingService', () => { }); describe('calculateTimeout', () => { - const logger = new Logger({ useMemoryLogger: true, name: 'test' }); + const logger = new Logger({ useMemoryLogger: true, name: 'test' }).getRawLogger(); const functionUnderTest = calculateTimeout(logger); afterEach(() => { delete process.env.SFDX_SOURCE_MEMBER_POLLING_TIMEOUT; diff --git a/yarn.lock b/yarn.lock index 2d645b62..68a7860a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -598,14 +598,14 @@ strip-ansi "6.0.1" ts-retry-promise "^0.8.0" -"@salesforce/core@^7.3.1", "@salesforce/core@^7.3.5", "@salesforce/core@^7.3.8": - version "7.3.8" - resolved "https://registry.yarnpkg.com/@salesforce/core/-/core-7.3.8.tgz#8a646b5321f08c0fb4d22e2fa8b1d60b3a20df9b" - integrity sha512-VWhXHfjwjtC3pJWYp8wt5/fnNQ5tK61ovMG5eteXzVD2oFd7og1f6YjwuAzoYIZK7kYWWv7KJfGtCsPs7Zw+Ww== +"@salesforce/core@^7.3.5", "@salesforce/core@^7.3.8", "@salesforce/core@^7.3.9": + version "7.3.9" + resolved "https://registry.yarnpkg.com/@salesforce/core/-/core-7.3.9.tgz#8abe2b3e2393989d11e92b7a6b96043fc9d5b9c8" + integrity sha512-eJqDiA5b7wU50Ee/xjmGzSnHrNVJ8S77B7enfX30gm7gxU3i3M3QeBdiV6XAOPLSIL96DseofP6Tv6c+rljlKA== dependencies: "@jsforce/jsforce-node" "^3.2.0" "@salesforce/kit" "^3.1.1" - "@salesforce/schemas" "^1.7.0" + "@salesforce/schemas" "^1.9.0" "@salesforce/ts-types" "^2.0.9" ajv "^8.13.0" change-case "^4.1.2" @@ -671,15 +671,15 @@ resolved "https://registry.yarnpkg.com/@salesforce/prettier-config/-/prettier-config-0.0.3.tgz#ba648d4886bb38adabe073dbea0b3a91b3753bb0" integrity sha512-hYOhoPTCSYMDYn+U1rlEk16PoBeAJPkrdg4/UtAzupM1mRRJOwEPMG1d7U8DxJFKuXW3DMEYWr2MwAIBDaHmFg== -"@salesforce/schemas@^1.7.0": - version "1.7.0" - resolved "https://registry.yarnpkg.com/@salesforce/schemas/-/schemas-1.7.0.tgz#b7e0af3ee414ae7160bce351c0184d77ccb98fe3" - integrity sha512-Z0PiCEV55khm0PG+DsnRYCjaDmacNe3HDmsoSm/CSyYvJJm+D5vvkHKN9/PKD/gaRe8XAU836yfamIYFblLINw== +"@salesforce/schemas@^1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@salesforce/schemas/-/schemas-1.9.0.tgz#ba477a112653a20b4edcf989c61c57bdff9aa3ca" + integrity sha512-LiN37zG5ODT6z70sL1fxF7BQwtCX9JOWofSU8iliSNIM+WDEeinnoFtVqPInRSNt8I0RiJxIKCrqstsmQRBNvA== -"@salesforce/source-deploy-retrieve@^11.4.4": - version "11.4.4" - resolved "https://registry.yarnpkg.com/@salesforce/source-deploy-retrieve/-/source-deploy-retrieve-11.4.4.tgz#c853e0888c6a5b64c4af3e705010ef1a6dac4c13" - integrity sha512-6dohRR9t6Aj2mbHzfYtbphxqxF83AwmAjkFFQPB6+Yn1ceVKmJjd0WY23fgWTTaTum+2pnw9XA35qwu4naBCVw== +"@salesforce/source-deploy-retrieve@^11.6.1": + version "11.6.1" + resolved "https://registry.yarnpkg.com/@salesforce/source-deploy-retrieve/-/source-deploy-retrieve-11.6.1.tgz#381d7ecb41025fee71db32e765b8fbf434255a4d" + integrity sha512-7v52S871V0fzIABxWmcvbI4iELTAyniiBM0+HHAvwO2rGclULKIf4IgkomL4l4Hz4BPd2v0fRlLJ4INkG/3+sA== dependencies: "@salesforce/core" "^7.3.5" "@salesforce/kit" "^3.1.1" @@ -2238,12 +2238,12 @@ eslint-plugin-jsdoc@^46.10.1: semver "^7.5.4" spdx-expression-parse "^4.0.0" -eslint-plugin-sf-plugin@^1.18.3: - version "1.18.3" - resolved "https://registry.yarnpkg.com/eslint-plugin-sf-plugin/-/eslint-plugin-sf-plugin-1.18.3.tgz#8711ba1544e86fb8227375415865fca2c3566348" - integrity sha512-Cl2ZpraMOwOm/kDn2hlud7mkDH3OrImueAyX8nkX1LA0kFma9/yokdxabWE/uaPpWPUlADeqgKWwgTjgf75SYQ== +eslint-plugin-sf-plugin@^1.18.4: + version "1.18.4" + resolved "https://registry.yarnpkg.com/eslint-plugin-sf-plugin/-/eslint-plugin-sf-plugin-1.18.4.tgz#59a41e224d620e20d0fe0e3902c43208c2629037" + integrity sha512-bPYmEh+5ARunhIfBoHc9UqrvPslRcYcloXJRKWqVkvU8tIBAiq2lqp6GWjVuUMPGjhvtUgICMolp6ozjO9wvmA== dependencies: - "@salesforce/core" "^7.3.1" + "@salesforce/core" "^7.3.8" "@typescript-eslint/utils" "^6.17.0" eslint-plugin-unicorn@^50.0.1: @@ -5178,16 +5178,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== @@ -5246,14 +5237,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== @@ -5770,7 +5754,7 @@ workerpool@6.2.1: resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343" integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw== -"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== @@ -5788,15 +5772,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"