From abf40f2152dbe63ba907410f19bf37a71cb18aa0 Mon Sep 17 00:00:00 2001 From: Steve Hetzel Date: Tue, 5 Dec 2023 16:18:00 -0700 Subject: [PATCH] fix: pass org data when building ComponentSet with wildcard metadata (#824) * fix: pass org data when building ComponentSet with wildcard metadata * chore: bump SDR version * chore: refactor long fn out * refactor: naming, spread like other props --------- Co-authored-by: mshanemc --- package.json | 2 +- src/commands/project/retrieve/start.ts | 9 +++++ test/commands/retrieve/start.test.ts | 17 +++++++++ test/nuts/deploy/metadata.nut.ts | 51 ++++++++++++++++++++++++++ test/nuts/retrieve/metadata.nut.ts | 43 ++++++++++++++++++++++ yarn.lock | 38 +++++++++---------- 6 files changed, 140 insertions(+), 20 deletions(-) create mode 100644 test/nuts/deploy/metadata.nut.ts diff --git a/package.json b/package.json index 7a9bf256..6c7c0db1 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "@salesforce/core": "^6.2.0", "@salesforce/kit": "^3.0.15", "@salesforce/sf-plugins-core": "^5.0.5", - "@salesforce/source-deploy-retrieve": "^10.0.3", + "@salesforce/source-deploy-retrieve": "^10.1.0", "@salesforce/source-tracking": "^5.1.0", "chalk": "^5.3.0" }, diff --git a/src/commands/project/retrieve/start.ts b/src/commands/project/retrieve/start.ts index fd419ab8..8ffcda2a 100644 --- a/src/commands/project/retrieve/start.ts +++ b/src/commands/project/retrieve/start.ts @@ -373,6 +373,8 @@ const buildRetrieveAndDeleteTargets = async ( } return result; } else { + const retrieveFromOrg = flags.metadata?.some(isRegexMatch) ? flags['target-org'].getUsername() : undefined; + return { componentSetFromNonDeletes: await ComponentSetBuilder.build({ sourceapiversion: ( @@ -399,6 +401,7 @@ const buildRetrieveAndDeleteTargets = async ( }, } : {}), + ...(retrieveFromOrg ? { org: { username: retrieveFromOrg, exclude: [] } } : {}), }), }; } @@ -435,3 +438,9 @@ const buildRetrieveOptions = async ( output: output ?? (await SfProject.resolve()).getDefaultPackage().fullPath, }), }); + +// check if we're retrieving metadata based on a pattern ... +const isRegexMatch = (mdEntry: string): boolean => { + const mdName = mdEntry.split(':')[1]; + return mdName?.includes('*') && mdName?.length > 1 && !mdName?.includes('.*'); +}; diff --git a/test/commands/retrieve/start.test.ts b/test/commands/retrieve/start.test.ts index f71211bf..dbfdfceb 100644 --- a/test/commands/retrieve/start.test.ts +++ b/test/commands/retrieve/start.test.ts @@ -169,6 +169,23 @@ describe('project retrieve start', () => { ensureRetrieveArgs({ format: 'source' }); }); + it('should pass along metadata and org for wildcard matching', async () => { + const metadata = ['ApexClass:MyC*']; + const result = await RetrieveMetadata.run(['--metadata', metadata[0], '--json']); + expect(result).to.deep.equal(expectedResults); + ensureCreateComponentSetArgs({ + metadata: { + metadataEntries: metadata, + directoryPaths: [expectedDirectoryPath], + }, + org: { + username: testOrg.username, + exclude: [], + }, + }); + ensureRetrieveArgs({ format: 'source' }); + }); + it('should pass along manifest', async () => { const manifest = 'package.xml'; const result = await RetrieveMetadata.run(['--manifest', manifest, '--json']); diff --git a/test/nuts/deploy/metadata.nut.ts b/test/nuts/deploy/metadata.nut.ts new file mode 100644 index 00000000..dfa818f8 --- /dev/null +++ b/test/nuts/deploy/metadata.nut.ts @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2023, 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 { fileURLToPath } from 'node:url'; +import { expect } from 'chai'; +import { SourceTestkit } from '@salesforce/source-testkit'; +import { DeployResultJson } from '../../../src/utils/types.js'; + +describe('deploy metadata NUTs', () => { + let testkit: SourceTestkit; + + before(async () => { + testkit = await SourceTestkit.create({ + repository: 'https://github.com/trailheadapps/dreamhouse-lwc.git', + nut: fileURLToPath(import.meta.url), + }); + await testkit.deploy({ args: '--source-dir force-app', exitCode: 0 }); + }); + + after(async () => { + await testkit?.clean(); + }); + + it('should deploy ApexClasses from wildcard match (single character)', async () => { + const response = await testkit.deploy({ args: '--metadata "ApexClass:P*"' }); + expect(response?.status).to.equal(0); + const result = response?.result as unknown as DeployResultJson; + expect(result.success).to.be.true; + expect(result.files.length).to.equal(4); + result.files.forEach((f) => { + expect(f.type).to.equal('ApexClass'); + expect(['PagedResult', 'PropertyController']).to.include(f.fullName); + }); + }); + + it('should deploy ApexClasses from wildcard match (2 characters)', async () => { + const response = await testkit.deploy({ args: '--metadata "ApexClass:Pa*"' }); + expect(response?.status).to.equal(0); + const result = response?.result as unknown as DeployResultJson; + expect(result.success).to.be.true; + expect(result.files.length).to.equal(2); + result.files.forEach((f) => { + expect(f.type).to.equal('ApexClass'); + expect(f.fullName).to.equal('PagedResult'); + }); + }); +}); diff --git a/test/nuts/retrieve/metadata.nut.ts b/test/nuts/retrieve/metadata.nut.ts index 8b2bad21..bad269f7 100644 --- a/test/nuts/retrieve/metadata.nut.ts +++ b/test/nuts/retrieve/metadata.nut.ts @@ -11,6 +11,7 @@ import { fileURLToPath } from 'node:url'; import { execCmd } from '@salesforce/cli-plugins-testkit'; import { SourceTestkit } from '@salesforce/source-testkit'; import { expect } from 'chai'; +import { RetrieveResultJson } from '../../../src/utils/types.js'; const ELECTRON = { id: '04t6A000002zgKSQAY', name: 'ElectronBranding' }; @@ -57,6 +58,48 @@ describe('retrieve metadata NUTs', () => { await testkit.retrieve({ args: '--metadata ApexClass AuraDefinitionBundle --output-dir myOutput' }); await testkit.expect.filesToBeRetrieved(['myOutput/classes/*', 'myOutput/aura/**/*']); }); + + it('should retrieve ApexClasses from wildcard match', async () => { + const response = await testkit.retrieve({ args: '--metadata "ApexClass:Test*"' }); + expect(response?.status).to.equal(0); + const result = response?.result as unknown as RetrieveResultJson; + expect(result.success).to.be.true; + expect(result.files.length).to.equal(4); + result.files.forEach((f) => { + expect(f.type).to.equal('ApexClass'); + expect(['TestSampleDataController', 'TestPropertyController']).to.include(f.fullName); + }); + await testkit.expect.filesToBeRetrieved(['force-app/main/default/classes/Test*']); + }); + + it('should retrieve ApexClasses from wildcard match without already existing in the project', async () => { + const forceAppDir = path.join(testkit.projectDir, 'force-app'); + const forceAppDirTmp = path.join(testkit.projectDir, 'force-app-tmp'); + + try { + fs.cpSync(forceAppDir, forceAppDirTmp, { recursive: true }); + fs.rmSync(forceAppDir, { recursive: true, force: true }); + expect(fs.existsSync(forceAppDir)).to.be.false; + const defaultDir = path.join(forceAppDir, 'main', 'default'); + fs.mkdirSync(defaultDir, { recursive: true }); + + const response = await testkit.retrieve({ args: '--metadata "ApexClass:Test*"' }); + expect(response?.status).to.equal(0); + const result = response?.result as unknown as RetrieveResultJson; + expect(result.success).to.be.true; + expect(result.files.length).to.equal(4); + result.files.forEach((f) => { + expect(f.type).to.equal('ApexClass'); + expect(['TestSampleDataController', 'TestPropertyController']).to.include(f.fullName); + }); + await testkit.expect.filesToBeRetrieved(['force-app/main/default/classes/Test*']); + } finally { + if (fs.existsSync(forceAppDirTmp)) { + fs.cpSync(forceAppDirTmp, forceAppDir, { recursive: true }); + fs.rmSync(forceAppDirTmp, { recursive: true, force: true }); + } + } + }); }); describe('--manifest flag', () => { diff --git a/yarn.lock b/yarn.lock index 5e1f6c00..69981232 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1013,21 +1013,21 @@ semver "^7.5.4" ts-retry-promise "^0.7.1" -"@salesforce/core@^6.1.0", "@salesforce/core@^6.1.3", "@salesforce/core@^6.2.0": - version "6.2.0" - resolved "https://registry.yarnpkg.com/@salesforce/core/-/core-6.2.0.tgz#9bac72c0b48c733cf1d32d19f9775c34d895f207" - integrity sha512-HuggjBCLA18yXYHChnsrPDGbM+fAPx+9NeS7Dkx3/o1VhJ2hok5BUkvdaeoAVex/0Oc2J+KcvX/gqrjY51iOhQ== +"@salesforce/core@^6.1.0", "@salesforce/core@^6.1.3", "@salesforce/core@^6.2.0", "@salesforce/core@^6.2.2": + version "6.3.0" + resolved "https://registry.yarnpkg.com/@salesforce/core/-/core-6.3.0.tgz#94613dcdcf70e8061bbdc4aa9f0f0ad605ebb51e" + integrity sha512-PLPDWRXbLi+ECNER6NHLTK/Ed9tMndmyVbBTE0/vyErXtCCPF6aSNyUmvFT1NrIZRrYA9p/QRHOtYUO7kPG4zg== dependencies: "@salesforce/kit" "^3.0.15" "@salesforce/schemas" "^1.6.1" "@salesforce/ts-types" "^2.0.9" - "@types/semver" "^7.5.4" + "@types/semver" "^7.5.6" ajv "^8.12.0" change-case "^4.1.2" faye "^1.4.0" form-data "^4.0.0" js2xmlparser "^4.0.1" - jsforce "^2.0.0-beta.28" + jsforce "^2.0.0-beta.29" jsonwebtoken "9.0.2" jszip "3.10.1" pino "^8.16.2" @@ -1148,12 +1148,12 @@ chalk "^4" inquirer "^8.2.5" -"@salesforce/source-deploy-retrieve@^10.0.0", "@salesforce/source-deploy-retrieve@^10.0.2", "@salesforce/source-deploy-retrieve@^10.0.3": - version "10.0.3" - resolved "https://registry.yarnpkg.com/@salesforce/source-deploy-retrieve/-/source-deploy-retrieve-10.0.3.tgz#bd95e15a78ef08e4ade5f96b2846c0137cccf8bb" - integrity sha512-7YgGd2CpOTYXdbtoB31eJEylYl1gbZvMqzbw8VjK1OVcywzuFUA43xznxzrSyFsBZZO6QAUAKyxoxxYR9goTyg== +"@salesforce/source-deploy-retrieve@^10.0.0", "@salesforce/source-deploy-retrieve@^10.0.2", "@salesforce/source-deploy-retrieve@^10.1.0": + version "10.1.0" + resolved "https://registry.yarnpkg.com/@salesforce/source-deploy-retrieve/-/source-deploy-retrieve-10.1.0.tgz#12dcc9096e14b11809f22594499d82649de6f8c5" + integrity sha512-oa9LCWlijwL0Lm5TKeDSOxY5lSAHsp92BfywdXtlMddUjHVQuVWYQHCiiiOiGDzv23iCnmWe455/AVS9stxbSQ== dependencies: - "@salesforce/core" "^6.2.0" + "@salesforce/core" "^6.2.2" "@salesforce/kit" "^3.0.15" "@salesforce/ts-types" "^2.0.9" fast-levenshtein "^3.0.0" @@ -1549,10 +1549,10 @@ dependencies: "@types/node" "*" -"@types/semver@^7.3.12", "@types/semver@^7.5.0", "@types/semver@^7.5.4": - version "7.5.4" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.4.tgz#0a41252ad431c473158b22f9bfb9a63df7541cff" - integrity sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ== +"@types/semver@^7.3.12", "@types/semver@^7.5.0", "@types/semver@^7.5.4", "@types/semver@^7.5.6": + version "7.5.6" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.6.tgz#c65b2bfce1bec346582c07724e3f8c1017a20339" + integrity sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A== "@types/shelljs@^0.8.15": version "0.8.15" @@ -4955,10 +4955,10 @@ jsesc@~0.5.0: resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA== -jsforce@^2.0.0-beta.28: - version "2.0.0-beta.28" - resolved "https://registry.yarnpkg.com/jsforce/-/jsforce-2.0.0-beta.28.tgz#5fd8d9b8e5efc798698793b147e00371f3d74e8f" - integrity sha512-tTmKRhr4yWNinhmurY/tiiltLFQq9RQ+gpYAt3wjFdCGjzd49/wqYQIFw4SsI3+iLjxXnc0uTgGwdAkDjxDWnA== +jsforce@^2.0.0-beta.28, jsforce@^2.0.0-beta.29: + version "2.0.0-beta.29" + resolved "https://registry.yarnpkg.com/jsforce/-/jsforce-2.0.0-beta.29.tgz#0b59b026eb0b90dfb199a53656af32a4c8acc48f" + integrity sha512-Fq7xjOYOikyozZZDQNTfzsAdhcO0rUXwtavsjM+cCYUFiCMVOJJavgco303zOsJk3v8sdAYnGgHyKckLIhnyAg== dependencies: "@babel/runtime" "^7.12.5" "@babel/runtime-corejs3" "^7.12.5"