Skip to content

Commit

Permalink
feat: no shelljs (#800)
Browse files Browse the repository at this point in the history
* chore: updates from devScripts

* chore: linter changes

* feat: no shelljs

* chore: bump stl

* test: nut failure fixes

* test: set the cli on more commands

* chore: lockfile

* test: cli in more places for source:* not found

---------

Co-authored-by: svc-cli-bot <[email protected]>
  • Loading branch information
mshanemc and svc-cli-bot authored Nov 7, 2023
1 parent 919e03a commit 3ddbe62
Show file tree
Hide file tree
Showing 13 changed files with 100 additions and 61 deletions.
12 changes: 5 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,17 @@
"dependencies": {
"@oclif/core": "^2.15.0",
"@salesforce/apex-node": "^2.1.0",
"@salesforce/core": "^5.3.16",
"@salesforce/core": "^5.3.18",
"@salesforce/kit": "^3.0.15",
"@salesforce/sf-plugins-core": "^3.1.22",
"@salesforce/source-deploy-retrieve": "^9.8.1",
"@salesforce/source-tracking": "^4.2.20",
"@salesforce/source-deploy-retrieve": "^9.8.4",
"@salesforce/source-tracking": "^4.3.0",
"chalk": "^4.1.2",
"shelljs": "^0.8.5",
"tslib": "^2"
},
"devDependencies": {
"@oclif/plugin-command-snapshot": "^4.0.12",
"@salesforce/cli-plugins-testkit": "^4.4.12",
"@salesforce/cli-plugins-testkit": "^5.0.2",
"@salesforce/dev-scripts": "^6.0.3",
"@salesforce/plugin-command-reference": "^3.0.40",
"@salesforce/plugin-settings": "^1.4.37",
Expand All @@ -29,9 +28,8 @@
"@salesforce/ts-sinon": "1.4.15",
"@salesforce/ts-types": "^2.0.8",
"@swc/core": "1.3.39",
"@types/shelljs": "^0.8.14",
"cross-env": "^7.0.3",
"eslint-plugin-sf-plugin": "^1.16.13",
"eslint-plugin-sf-plugin": "^1.16.14",
"jsforce": "^2.0.0-beta.28",
"oclif": "^3.16.0",
"shx": "0.3.4",
Expand Down
7 changes: 3 additions & 4 deletions src/commands/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import { EOL } from 'node:os';
import { writeFile, readFile } from 'node:fs/promises';
import { existsSync } from 'node:fs';
import { exec } from 'node:child_process';
import { Hook } from '@oclif/core';
import { Messages } from '@salesforce/core';
import { Env, parseJsonMap } from '@salesforce/kit';
Expand All @@ -21,9 +22,7 @@ import {
SfHook,
Flags,
} from '@salesforce/sf-plugins-core';
import { exec } from 'shelljs';
import { DeployerResult } from '@salesforce/sf-plugins-core/lib/deployer';

Messages.importMessagesDirectory(__dirname);

const messages = Messages.loadMessages('@salesforce/plugin-deploy-retrieve', 'deploy');
Expand Down Expand Up @@ -144,8 +143,8 @@ export default class Deploy extends SfCommand<void> {
const addition = `${EOL}${EOL}# Deploy Options${EOL}${DEPLOY_OPTIONS_FILE}${EOL}`;
await writeFile('.gitignore', `${gitignore}${addition}`);
}
exec('git add .gitignore', { silent: true });
exec(`git commit -am "Add ${DEPLOY_OPTIONS_FILE} to .gitignore"`, { silent: true });
exec('git add .gitignore');
exec(`git commit -am "Add ${DEPLOY_OPTIONS_FILE} to .gitignore"`);
}

// this used to be async when it was using fs-extra. Presered public api
Expand Down
36 changes: 17 additions & 19 deletions test/nuts/delete/source.nut.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import * as path from 'node:path';
import { expect } from 'chai';
import { execCmd, TestSession } from '@salesforce/cli-plugins-testkit';
import { SourceTestkit } from '@salesforce/source-testkit';
import { exec } from 'shelljs';
import { FileResponse } from '@salesforce/source-deploy-retrieve';
import { AuthInfo, Connection } from '@salesforce/core';
import { ensureArray } from '@salesforce/ts-types';
Expand Down Expand Up @@ -40,7 +39,7 @@ describe('CustomLabels', () => {
scratchOrgs: [{ setDefault: true, config: path.join('config', 'project-scratch-def.json') }],
devhubAuthStrategy: 'AUTO',
});
execCmd('force:source:deploy --sourcepath force-app', { ensureExitCode: 0 });
execCmd('project:deploy:start --source-dir force-app', { ensureExitCode: 0 });
});

after(async () => {
Expand Down Expand Up @@ -102,8 +101,9 @@ describe('project delete source NUTs', () => {
const pathToClass = path.join(testkit.projectDir, output, `${apexName}.cls`);
execCmd(`force:apex:class:create --classname ${apexName} --outputdir ${output} --api-version 58.0`, {
ensureExitCode: 0,
cli: 'sf',
});
execCmd(`force:source:deploy -m ApexClass:${apexName}`, { ensureExitCode: 0 });
execCmd(`project:deploy:start -m ApexClass:${apexName}`, { ensureExitCode: 0 });
return { apexName, output, pathToClass };
};

Expand All @@ -112,7 +112,7 @@ describe('project delete source NUTs', () => {
nut: __filename,
repository: 'https://github.com/trailheadapps/dreamhouse-lwc.git',
});
execCmd('force:source:deploy --sourcepath force-app', { ensureExitCode: 0 });
execCmd('project:deploy:start --source-dir force-app', { ensureExitCode: 0 });
});

after(async () => {
Expand Down Expand Up @@ -184,16 +184,14 @@ describe('project delete source NUTs', () => {
it('should source:delete a remote-only ApexClass from the org', async () => {
const { apexName, pathToClass } = createApexClass();
const query = () =>
JSON.parse(
exec(
`sf data:query -q "SELECT IsNameObsolete FROM SourceMember WHERE MemberType='ApexClass' AND MemberName='${apexName}' LIMIT 1" -t --json`,
{ silent: true }
)
) as { result: { records: Array<{ IsNameObsolete: boolean }> } };

let soql = query();
execCmd<{ records: Array<{ IsNameObsolete: boolean }> }>(
`data:query -q "SELECT IsNameObsolete FROM SourceMember WHERE MemberType='ApexClass' AND MemberName='${apexName}' LIMIT 1" -t --json`,
{ silent: true, cli: 'sf', ensureExitCode: 0 }
);

let soql = query().jsonOutput?.result;
// the ApexClass is present in the org
expect(soql.result.records[0].IsNameObsolete).to.be.false;
expect(soql?.records[0].IsNameObsolete).to.be.false;
await testkit.deleteGlobs(['force-app/main/default/classes/myApexClass.*']);
const response = execCmd<DeleteSourceJson>(
`project:delete:source --json --no-prompt --metadata ApexClass:${apexName}`,
Expand All @@ -204,9 +202,9 @@ describe('project delete source NUTs', () => {
// remote only delete won't have an associated filepath
expect(response?.deletedSource).to.have.length(0);
expect(fs.existsSync(pathToClass)).to.be.false;
soql = query();
soql = query().jsonOutput?.result;
// the apex class has been deleted in the org
expect(soql.result.records[0].IsNameObsolete).to.be.true;
expect(soql?.records[0].IsNameObsolete).to.be.true;
});

it('should NOT delete local files with --checkonly', () => {
Expand Down Expand Up @@ -241,7 +239,7 @@ describe('project delete source NUTs', () => {
// use the brokerCard LWC
const lwcPath = path.join(testkit.projectDir, 'force-app', 'main', 'default', 'lwc', 'brokerCard', 'helper.js');
fs.writeFileSync(lwcPath, '//', { encoding: 'utf8' });
execCmd(`force:source:deploy -p ${lwcPath}`);
execCmd(`project:deploy:start --source-dir ${lwcPath}`, { cli: 'sf', ensureExitCode: 0 });
const deleteResult = execCmd<{ deletedSource: [FileResponse] }>(
`project:delete:source -p ${lwcPath} --no-prompt --json`
).jsonOutput?.result;
Expand All @@ -261,7 +259,7 @@ describe('project delete source NUTs', () => {
const lwcPath2 = path.join(testkit.projectDir, 'force-app', 'main', 'default', 'lwc', 'daysOnMarket', 'helper.js');
fs.writeFileSync(lwcPath1, '//', { encoding: 'utf8' });
fs.writeFileSync(lwcPath2, '//', { encoding: 'utf8' });
execCmd(`force:source:deploy -p ${lwcPath1},${lwcPath2}`);
execCmd(`project:deploy:start --source-dir ${lwcPath1} --source-dir ${lwcPath2}`);
// delete both helper.js files at the same time
const deleteResult = execCmd<{ deletedSource: FileResponse[] }>(
// eslint-disable-next-line sf-plugin/no-execcmd-double-quotes
Expand All @@ -286,8 +284,8 @@ describe('project delete source NUTs', () => {
it('should delete an entire LWC', async () => {
const lwcPath = path.join(testkit.projectDir, 'force-app', 'main', 'default', 'lwc');
const mylwcPath = path.join(lwcPath, 'mylwc');
execCmd(`force:lightning:component:create -n mylwc --type lwc -d ${lwcPath}`);
execCmd(`force:source:deploy -p ${mylwcPath}`);
execCmd(`force:lightning:component:create -n mylwc --type lwc -d ${lwcPath}`, { cli: 'sf', ensureExitCode: 0 });
execCmd(`project:deploy:start --source-dir ${mylwcPath}`);
expect(await isNameObsolete(testkit.username, 'LightningComponentBundle', 'mylwc')).to.be.false;
const deleteResult = execCmd<{ deletedSource: [FileResponse] }>(
`project:delete:source -p ${mylwcPath} --no-prompt --json`
Expand Down
1 change: 1 addition & 0 deletions test/nuts/destructive/destructiveChanges.nut.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ describe('project deploy start --destructive NUTs', () => {
const pathToClass = path.join(testkit.projectDir, output, `${apexName}.cls`);
execCmd(`force:apex:class:create --classname ${apexName} --outputdir ${output} --api-version 58.0`, {
ensureExitCode: 0,
cli: 'sf',
});
execCmd(`project:deploy:start -m ApexClass:${apexName}`, { ensureExitCode: 0 });
return { apexName, output, pathToClass };
Expand Down
3 changes: 1 addition & 2 deletions test/nuts/generateNuts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

import * as path from 'node:path';
import * as fs from 'node:fs';
import * as shelljs from 'shelljs';
import { RepoConfig, TEST_REPOS_MAP } from './testMatrix';

const SEED_FILTER = process.env.PLUGIN_DEPLOY_RETRIEVE_SEED_FILTER ?? '';
Expand Down Expand Up @@ -41,7 +40,7 @@ function generateNut(generatedDir: string, seedName: string, seedContents: strin

function generateNuts(): void {
const generatedDir = path.resolve(__dirname, 'generated');
shelljs.rm('-rf', generatedDir);
fs.rmSync(generatedDir, { recursive: true, force: true });
fs.mkdirSync(generatedDir, { recursive: true });
const seeds = getSeedFiles();
for (const seed of seeds) {
Expand Down
4 changes: 2 additions & 2 deletions test/nuts/retrieve/metadata.nut.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@

import * as path from 'node:path';
import * as fs from 'node:fs';
import { execCmd } from '@salesforce/cli-plugins-testkit';
import { SourceTestkit } from '@salesforce/source-testkit';
import { exec } from 'shelljs';
import { expect } from 'chai';

const ELECTRON = { id: '04t6A000002zgKSQAY', name: 'ElectronBranding' };
Expand Down Expand Up @@ -78,7 +78,7 @@ describe('retrieve metadata NUTs', () => {

describe('--package-name flag', () => {
it('should retrieve an installed package', async () => {
exec(`sf force:package:install --noprompt --package ${ELECTRON.id} --wait 5 --json`, { silent: true });
execCmd(`force:package:install --noprompt --package ${ELECTRON.id} --wait 5 --json`, { silent: true, cli: 'sf' });

await testkit.retrieve({ args: `--package-name "${ELECTRON.name}"` });
await testkit.expect.packagesToBeRetrieved([ELECTRON.name]);
Expand Down
10 changes: 10 additions & 0 deletions test/nuts/tracking/basics.nut.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ describe('end-to-end-test for tracking with an org (single packageDir)', () => {
it('detects the initial metadata status', () => {
const result = execCmd<StatusResult[]>('force:source:status --json', {
ensureExitCode: 0,
cli: 'sf',
}).jsonOutput?.result;
assert(Array.isArray(result));
// the fields should be populated
Expand Down Expand Up @@ -92,11 +93,13 @@ describe('end-to-end-test for tracking with an org (single packageDir)', () => {
it('sees no local changes (all were committed from push), but profile updated in remote', () => {
const localResult = execCmd<StatusResult[]>('force:source:status --json --local', {
ensureExitCode: 0,
cli: 'sf',
}).jsonOutput?.result;
expect(localResult?.filter(filterIgnored)).to.deep.equal([]);

const remoteResult = execCmd<StatusResult[]>('force:source:status --json --remote', {
ensureExitCode: 0,
cli: 'sf',
}).jsonOutput?.result;
expect(remoteResult?.some((item) => item.type === 'Profile')).to.equal(true);
});
Expand All @@ -110,6 +113,7 @@ describe('end-to-end-test for tracking with an org (single packageDir)', () => {
it('sf sees no remote changes (all were committed from push) except Profile', () => {
const remoteResult = execCmd<StatusResult[]>('force:source:status --json --remote', {
ensureExitCode: 0,
cli: 'sf',
}).jsonOutput?.result;
expect(remoteResult?.some((item) => item.type === 'Profile')).to.equal(true);
});
Expand All @@ -127,6 +131,7 @@ describe('end-to-end-test for tracking with an org (single packageDir)', () => {
it('sees no local or remote changes', () => {
const result = execCmd<StatusResult[]>('force:source:status --json', {
ensureExitCode: 0,
cli: 'sf',
}).jsonOutput?.result;
expect(result?.filter((r) => r.type === 'Profile').filter(filterIgnored), JSON.stringify(result)).to.have.length(
0
Expand Down Expand Up @@ -155,6 +160,7 @@ describe('end-to-end-test for tracking with an org (single packageDir)', () => {
]);
const result = execCmd<StatusResult[]>('force:source:status --json --local', {
ensureExitCode: 0,
cli: 'sf',
}).jsonOutput?.result;
expect(result?.filter(filterIgnored)).to.deep.equal([
{
Expand Down Expand Up @@ -199,6 +205,7 @@ describe('end-to-end-test for tracking with an org (single packageDir)', () => {
it('does not see any change in remote status', () => {
const result = execCmd<StatusResult[]>('force:source:status --json --remote', {
ensureExitCode: 0,
cli: 'sf',
}).jsonOutput?.result;
expect(
result?.filter((r) => r.fullName === 'TestOrderController'),
Expand All @@ -224,6 +231,7 @@ describe('end-to-end-test for tracking with an org (single packageDir)', () => {
it('sees no local changes', () => {
const result = execCmd<StatusResult[]>('force:source:status --json --local', {
ensureExitCode: 0,
cli: 'sf',
}).jsonOutput?.result;
expect(result?.filter(filterIgnored), JSON.stringify(result)).to.be.an.instanceof(Array).with.length(0);
});
Expand All @@ -243,6 +251,7 @@ describe('end-to-end-test for tracking with an org (single packageDir)', () => {
assert(hubUsername, 'hubUsername should be defined');
const failure = execCmd(`force:source:status -u ${hubUsername} --remote --json`, {
ensureExitCode: 1,
cli: 'sf',
}).jsonOutput as unknown as { name: string };
// command5 is removing `Error` from the end of the error names.
expect(failure.name).to.include('NonSourceTrackedOrg');
Expand Down Expand Up @@ -281,6 +290,7 @@ describe('end-to-end-test for tracking with an org (single packageDir)', () => {
it('sees no local changes', () => {
const result = execCmd<StatusResult[]>('force:source:status --json --local', {
ensureExitCode: 0,
cli: 'sf',
}).jsonOutput?.result;
expect(result?.filter(filterIgnored), JSON.stringify(result)).to.be.an.instanceof(Array).with.length(2);
});
Expand Down
2 changes: 2 additions & 0 deletions test/nuts/tracking/conflicts.nut.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ describe('conflict detection and resolution', () => {
});
const result = execCmd<StatusResult[]>('force:source:status --json --remote', {
ensureExitCode: 0,
cli: 'sf',
}).jsonOutput?.result;
expect(
result?.filter((r) => r.type === 'CustomApplication'),
Expand All @@ -99,6 +100,7 @@ describe('conflict detection and resolution', () => {
it('can see the conflict in status', () => {
const result = execCmd<StatusResult[]>('force:source:status --json', {
ensureExitCode: 0,
cli: 'sf',
}).jsonOutput?.result.filter((app) => app.type === 'CustomApplication');
// json is not sorted. This relies on the implementation of getConflicts()
expect(result).to.deep.equal([
Expand Down
3 changes: 2 additions & 1 deletion test/nuts/tracking/deleteResetTracking.nut.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ describe('reset and clear tracking', () => {
it('runs status to start tracking', () => {
const result = execCmd('force:source:status --json', {
ensureExitCode: 0,
cli: 'sf',
}).jsonOutput?.result;
expect(result).to.have.length.greaterThan(100); // ebikes is big
});
Expand Down Expand Up @@ -109,7 +110,7 @@ describe('reset and clear tracking', () => {
}
});
// gets tracking files from server
execCmd('force:source:status --json --remote', { ensureExitCode: 0 });
execCmd('force:source:status --json --remote', { ensureExitCode: 0, cli: 'sf' });
const revisions = await getRevisionsAsArray();
const revisionFile = JSON.parse(
await fs.promises.readFile(path.join(trackingFileFolder, 'maxRevision.json'), 'utf8')
Expand Down
8 changes: 5 additions & 3 deletions test/nuts/tracking/forceIgnore.nut.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import * as path from 'node:path';
import * as fs from 'node:fs';
import { expect } from 'chai';
import * as shell from 'shelljs';

import { execCmd, TestSession } from '@salesforce/cli-plugins-testkit';
import { AuthInfo, Connection } from '@salesforce/core';
Expand Down Expand Up @@ -42,8 +41,8 @@ describe('forceignore changes', () => {
});

execCmd(`force:apex:class:create -n IgnoreTest --outputdir ${classdir} --api-version 58.0`, {
cli: 'sfdx',
ensureExitCode: 0,
cli: 'sf',
});
originalForceIgnore = await fs.promises.readFile(path.join(session.project.dir, '.forceignore'), 'utf8');
conn = await Connection.create({
Expand Down Expand Up @@ -73,6 +72,7 @@ describe('forceignore changes', () => {
it('shows the file in status as ignored', () => {
const output = execCmd<StatusResult>('force:source:status --json', {
ensureExitCode: 0,
cli: 'sf',
}).jsonOutput?.result;
expect(output, JSON.stringify(output)).to.deep.include({
state: 'Local Add',
Expand Down Expand Up @@ -107,9 +107,10 @@ describe('forceignore changes', () => {
await fs.promises.writeFile(path.join(session.project.dir, '.forceignore'), newForceIgnore);

// add a file in the local source
shell.exec(`sfdx force:apex:class:create -n UnIgnoreTest --outputdir ${classdir} --api-version 58.0`, {
execCmd(`force:apex:class:create -n UnIgnoreTest --outputdir ${classdir} --api-version 58.0`, {
cwd: session.project.dir,
silent: true,
cli: 'sf',
});
// another error when there's nothing to push
const output = execCmd<DeployResultJson>('deploy:metadata --json', {
Expand Down Expand Up @@ -157,6 +158,7 @@ describe('forceignore changes', () => {
// gets file into source tracking
const statusOutput = execCmd<StatusResult[]>('force:source:status --json --remote', {
ensureExitCode: 0,
cli: 'sf',
}).jsonOutput?.result;
expect(statusOutput?.some((result) => result.fullName === 'CreatedClass')).to.equal(true);
});
Expand Down
Loading

0 comments on commit 3ddbe62

Please sign in to comment.