generated from salesforcecli/plugin-template
-
Notifications
You must be signed in to change notification settings - Fork 18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Wr/destructive deploy #230
Merged
Merged
Changes from 1 commit
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
8f1a102
fix: implementing destructive change deploy, 1 NUT
WillieRuemmele 1fc0c35
chore: add NUTs, fix UTs
WillieRuemmele 82d5a0b
Merge branch 'main' into wr/destructiveDeploy
WillieRuemmele ff975d2
chore: post-review board updates
WillieRuemmele f9ba0ac
Merge branch 'wr/destructiveDeploy' of github.com:salesforcecli/plugi…
WillieRuemmele 576ff7f
chore: fix linting
WillieRuemmele d705e88
chore: minor updates to flag logic, redo NUT query method
WillieRuemmele 53b021f
chore: remove unnecessary checks in NUTs
WillieRuemmele ce8b4f4
Merge branch 'main' into wr/destructiveDeploy
WillieRuemmele 154cf90
chore: bump SDR to 5, include deploy:destructive in NUTs
WillieRuemmele File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,7 +10,7 @@ import * as os from 'os'; | |
import { expect } from 'chai'; | ||
import { execCmd } from '@salesforce/cli-plugins-testkit'; | ||
import { SourceTestkit } from '@salesforce/source-testkit'; | ||
import { exec } from 'shelljs'; | ||
import { AuthInfo, Connection } from '@salesforce/core'; | ||
|
||
describe('source:delete NUTs', () => { | ||
const executable = path.join(process.cwd(), 'bin', 'run'); | ||
|
@@ -29,16 +29,17 @@ describe('source:delete NUTs', () => { | |
execCmd(`force:source:manifest:create --metadata ${metadata} --manifesttype ${manifesttype}`); | ||
}; | ||
|
||
const query = ( | ||
memberType: string, | ||
memberName: string | ||
): { result: { records: Array<{ IsNameObsolete: boolean }> } } => { | ||
return JSON.parse( | ||
exec( | ||
`sfdx force:data:soql:query -q "SELECT IsNameObsolete FROM SourceMember WHERE MemberType='${memberType}' AND MemberName='${memberName}'" -t --json`, | ||
{ silent: true } | ||
) | ||
) as { result: { records: Array<{ IsNameObsolete: boolean }> } }; | ||
const isNameObsolete = async (memberType: string, memberName: string): Promise<boolean> => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. that turned out nice. |
||
const connection = await Connection.create({ | ||
authInfo: await AuthInfo.create({ username: testkit.username }), | ||
}); | ||
|
||
const res = await connection.singleRecordQuery<{ IsNameObsolete: boolean }>( | ||
`SELECT IsNameObsolete FROM SourceMember WHERE MemberType='${memberType}' AND MemberName='${memberName}'`, | ||
{ tooling: true } | ||
); | ||
|
||
return res.IsNameObsolete; | ||
}; | ||
|
||
before(async () => { | ||
|
@@ -57,48 +58,48 @@ describe('source:delete NUTs', () => { | |
describe('destructive changes POST', () => { | ||
it('should deploy and then delete an ApexClass ', async () => { | ||
const { apexName } = createApexClass(); | ||
let soql = query('ApexClass', apexName); | ||
let deleted = await isNameObsolete('ApexClass', apexName); | ||
|
||
expect(soql.result.records[0].IsNameObsolete).to.be.false; | ||
expect(deleted).to.be.false; | ||
createManifest('ApexClass:GeocodingService', 'package'); | ||
createManifest(`ApexClass:${apexName}`, 'post'); | ||
|
||
execCmd('force:source:deploy --json --manifest package.xml --postdestructivechanges destructiveChangesPost.xml', { | ||
ensureExitCode: 0, | ||
}); | ||
|
||
soql = query('ApexClass', apexName); | ||
expect(soql.result.records[0].IsNameObsolete).to.be.true; | ||
deleted = await isNameObsolete('ApexClass', apexName); | ||
expect(deleted).to.be.true; | ||
}); | ||
}); | ||
|
||
describe('destructive changes PRE', () => { | ||
it('should delete an ApexClass and then deploy a class', async () => { | ||
const { apexName } = createApexClass(); | ||
let soql = query('ApexClass', apexName); | ||
let deleted = await isNameObsolete('ApexClass', apexName); | ||
|
||
expect(soql.result.records[0].IsNameObsolete).to.be.false; | ||
expect(deleted).to.be.false; | ||
createManifest('ApexClass:GeocodingService', 'package'); | ||
createManifest(`ApexClass:${apexName}`, 'pre'); | ||
|
||
execCmd('force:source:deploy --json --manifest package.xml --predestructivechanges destructiveChangesPre.xml', { | ||
ensureExitCode: 0, | ||
}); | ||
|
||
soql = query('ApexClass', apexName); | ||
expect(soql.result.records[0].IsNameObsolete).to.be.true; | ||
deleted = await isNameObsolete('ApexClass', apexName); | ||
expect(deleted).to.be.true; | ||
}); | ||
}); | ||
|
||
describe('destructive changes POST and PRE', () => { | ||
it('should delete a class, then deploy and then delete an ApexClass', async () => { | ||
const pre = createApexClass('pre').apexName; | ||
const post = createApexClass('post').apexName; | ||
let soqlPre = query('ApexClass', pre); | ||
let soqlPost = query('ApexClass', post); | ||
let preDeleted = await isNameObsolete('ApexClass', pre); | ||
let postDeleted = await isNameObsolete('ApexClass', post); | ||
|
||
expect(soqlPre.result.records[0].IsNameObsolete).to.be.false; | ||
expect(soqlPost.result.records[0].IsNameObsolete).to.be.false; | ||
expect(preDeleted).to.be.false; | ||
expect(postDeleted).to.be.false; | ||
createManifest('ApexClass:GeocodingService', 'package'); | ||
createManifest(`ApexClass:${post}`, 'post'); | ||
createManifest(`ApexClass:${pre}`, 'pre'); | ||
|
@@ -110,30 +111,55 @@ describe('source:delete NUTs', () => { | |
} | ||
); | ||
|
||
soqlPre = query('ApexClass', pre); | ||
soqlPost = query('ApexClass', post); | ||
expect(soqlPre.result.records[0].IsNameObsolete).to.be.true; | ||
expect(soqlPost.result.records[0].IsNameObsolete).to.be.true; | ||
preDeleted = await isNameObsolete('ApexClass', pre); | ||
postDeleted = await isNameObsolete('ApexClass', post); | ||
expect(preDeleted).to.be.true; | ||
expect(postDeleted).to.be.true; | ||
}); | ||
}); | ||
|
||
describe('errors', () => { | ||
it('should throw an error when a destructive flag is passed without the manifest flag', () => { | ||
it('should throw an error when a pre destructive flag is passed without the manifest flag', async () => { | ||
const { apexName } = createApexClass(); | ||
const soql = query('ApexClass', apexName); | ||
const deleted = await isNameObsolete('ApexClass', apexName); | ||
mshanemc marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
expect(soql.result.records[0].IsNameObsolete).to.be.false; | ||
expect(deleted).to.be.false; | ||
createManifest('ApexClass:GeocodingService', 'package'); | ||
createManifest(`ApexClass:${apexName}`, 'pre'); | ||
|
||
try { | ||
execCmd('force:source:deploy --json --sourcepath force-app --predestructivechanges destructiveChangesPre.xml', { | ||
ensureExitCode: 0, | ||
}); | ||
execCmd('force:source:deploy --json --sourcepath force-app --predestructivechanges destructiveChangesPre.xml'); | ||
} catch (e) { | ||
const err = e as Error; | ||
expect(err).to.not.be.undefined; | ||
expect(err.message).to.include('Error: --manifest= must also be provided when using --predestructivechanges='); | ||
} | ||
}); | ||
|
||
it('should throw an error when a post destructive flag is passed without the manifest flag', async () => { | ||
const { apexName } = createApexClass(); | ||
const deleted = await isNameObsolete('ApexClass', apexName); | ||
|
||
expect(deleted).to.be.false; | ||
createManifest('ApexClass:GeocodingService', 'package'); | ||
createManifest(`ApexClass:${apexName}`, 'pre'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe you want to use the |
||
|
||
try { | ||
execCmd('force:source:deploy --json --sourcepath force-app --postdestructivechanges destructiveChangesPre.xml'); | ||
} catch (e) { | ||
const err = e as Error; | ||
expect(err).to.not.be.undefined; | ||
expect(err.message).to.include('Error: --manifest= must also be provided when using --postdestructivechanges='); | ||
} | ||
}); | ||
|
||
it("should throw an error when a destructive manifest is passed that doesn't exist", () => { | ||
try { | ||
execCmd('force:source:deploy --json --sourcepath force-app --predestructivechanges doesntexist.xml'); | ||
} catch (e) { | ||
const err = e as Error; | ||
expect(err).to.not.be.undefined; | ||
expect(err.message).to.include('Missing one of the following parameters: manifest'); | ||
expect(err.message).to.include("ENOENT: no such file or directory, open 'doesntexist.xml'"); | ||
} | ||
}); | ||
}); | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't you still need the xorFlag validations?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's handled in the
SourceCommand
base class still - that method overrode it to add the post/pre flag validation that's fixed withdependsOn
property in the flag definition