Skip to content
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

BREAKING CHANGE Wr/destructive changes #450

Merged
merged 14 commits into from
Oct 21, 2021
Merged

Conversation

WillieRuemmele
Copy link
Member

@WillieRuemmele WillieRuemmele commented Sep 13, 2021

What does this PR do?

BREAKING CHANGE:
breaks a few public methods' parameters
adds pre/post destructive change support to ComponentSet.fromManifest

What issues does this PR fix or reference?

@W-9892375@

Functionality Before

destructive component sets were limited to a single type (pre/post)

Functionality After

you can now specify which type of deletion per SourceComponent

@WillieRuemmele WillieRuemmele changed the title Wr/destructive changes BREAKING CHANGE Wr/destructive changes Sep 13, 2021
return this.destructiveChangesType;
}

public setMarkedForDelete(destructiveChangeType?: DestructiveChangesType | boolean): void {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as a setter, we need to be able to specify if it's a deletion (true/false) and what type of deletionDestructiveChangesType passing nothing will set it to true and a post delete

@@ -360,7 +402,7 @@ export class ComponentSet extends LazyCollection<MetadataComponent> {
>;
}

public add(component: ComponentLike, asDeletion?: boolean): void {
public add(component: ComponentLike, deletionType?: DestructiveChangesType): void {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

replacing the asDeletion param is the breaking change, which can also be seen on other methods

}
};

for (const component of manifest.components) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

write the manifest comps. and then the destructive post (if present) and the destructive pre (if present)

@@ -391,21 +404,21 @@ describe('MetadataConverter', () => {
]);
});

it('should write destructive changes pre manifest when ComponentSet has deletes', async () => {
it('should write destructive changes pre manifest when ComponentSet has deletes marked for pre', async () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit pick. Can you rename the similar test for post in line 167?

@@ -76,11 +79,11 @@ export class ComponentSet extends LazyCollection<MetadataComponent> {
this.logger = Logger.childFromRoot(this.constructor.name);

for (const component of components) {
let asDeletion = false;
let destructiveType = this.destructiveChangesType;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is an "if-else" assignment, a turnery operation can be used here.

const destructiveType = (component instanceof SourceComponent)
  ? component.getDestructiveChangesType(),
  : this.destructiveChangesType;

for (const path of paths) {
for (const component of resolver.getComponentsFromPath(path, inclusiveFilter)) {
set.add(component, asDeletes);
set.add(component, destructiveType);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just dbl-checking here, as I'm not clear on the code paths - since destructiveType is nullable, what happens when set.add(component, null) is called and then later used?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it should default to a POST i.e. generating a destructiveChangesPost.xml

// If this ComponentSet has components marked for delete, we need to
// only include those components in a destructiveChanges.xml and
// all other components in the regular manifest.
let components = this.components;
if (this.hasDeletes) {
if (forDestructiveChanges) {
components = this.destructiveComponents;
if (destructiveType) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A turnery operation can be used here

@@ -168,23 +171,62 @@ export class ComponentSet extends LazyCollection<MetadataComponent> {
public static async fromManifest(input: string | FromManifestOptions): Promise<ComponentSet> {
const manifestPath = typeof input === 'string' ? input : input.manifestPath;
const options = (typeof input === 'object' ? input : {}) as Partial<FromManifestOptions>;
let manifestPre;
let manifestPost;
const hasManifestPre = !!options.destructivePre;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could the conditionals below could refer back to options.destructivePre/Post for truthiness, rather than creating extra constants?


const manifestResolver = new ManifestResolver(options.tree, options.registry);
const manifest = await manifestResolver.resolve(manifestPath);
if (hasManifestPre) {
manifestPre = await manifestResolver.resolve(options.destructivePre);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggest

const manifestPre = options.destructivePost ? await manifestResolver.resolve(options.destructivePre) : undefined;

then you could even refer to the truthiness of manifestPre further down

it's cleaner if everything can stay const

Copy link
Contributor

@mshanemc mshanemc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

most of the comments are just style stuff and concision or ideas.

setMarkedForDelete and getTypesOfDestructiveChanges are the only actual problems I saw.

if (!this.destructiveComponents.has(key)) {
this.destructiveComponents.set(key, new Map<string, SourceComponent>());
const deletions = this.destructiveComponents[deletionType];
if (!deletions.has(key)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have some feelings about 3 levels of if

  1. since we don't do anything for not if (component instanceof SourceComponent) we could flip that and return;

  2. the non deletionType is simple...we could do that and then return (currently 424-427);

then handle all the delete logic (the least likely branch to get used)

// something could try adding a component meant for deletion improperly, which would be marked as an addition
// specifically the ComponentSet.fromManifest with the `resolveSourcePaths` options which calls
// ComponentSet.fromSource, and adds everything as an addition
if (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, maybe I understand the flow logic now that I read down to here. Maybe this could be a function that could run on the delete and non-delete path?

Or those paths could check for existence on its counterpart (deletion would delete it from manifestComponents and non-deletion would just not add it if it's already in deletions?)

*
* @return DestructiveChangesType[]
*/
public getTypesOfDestructiveChanges(): DestructiveChangesType[] {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hasDeletes is doing pretty much the same logic, and is checked in both the Converter and CS's getObject.

This could also return an empty array for "there are none" so there is only one.

As written, if you were to NOT check hasDeletes before asking getTypesOfDestructiveChanges, your CS would tell that both types are present (the else condition here).

suggestion: make an array, and conditionally push to it (there might be 0,1, or 2 values).

then we can eliminate the hasDeletes since this code would have no effect for an empty array.

const destructiveChangesTypes = cs.getTypesOfDestructiveChanges();
              destructiveChangesTypes.map((destructiveChangesType) => {

@@ -103,13 +102,19 @@ export class MetadataConverter {
if (!isSource) {
const manifestPath = join(packagePath, MetadataConverter.PACKAGE_XML_FILE);
tasks.push(promises.writeFile(manifestPath, manifestContents));

// For deploying destructive changes
if (cs.hasDeletes) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see comments on CS about hasDeletes and getTypesOfDestructiveChanges

) {
this.markedForDelete = true;
this.destructiveChangesType =
(destructiveChangeType as DestructiveChangesType) || DestructiveChangesType.POST;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if true is passed in, you're making an invalid type assertion true as DestructiveChangesType.

What all would the else condition handle? false only? If so, maybe invert the order and return early?

then you could have this.markedForDelete = true (because it's not false)
and then everything except PRE would mean POST, right?

@@ -60,7 +60,7 @@ describe('SourceComponent', () => {
it('should return correct markedForDelete status', () => {
expect(COMPONENT.isMarkedForDelete()).to.be.false;
try {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this would be a good place to try out the other set values (destructive types, true)

Copy link
Contributor

@mshanemc mshanemc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

most of the comments are just style stuff and concision or ideas.

setMarkedForDelete and getTypesOfDestructiveChanges are the only actual problems I saw.

name: component.fullName,
}),
DestructiveChangesType.POST
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method has doubled in size and I think we can make it more DRY by extracting some of the destructive changes logic into a private method. The above conditionals are nearly identical.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
);
const resolveDestructiveChanges = (option, type) => {
const manifest = await manifestResolver.resolve(option);
for (const comp of manifest.components) {
addComponent(new SourceComponent({ type: comp.type, name: comp.fullName }), type);
}
};
if (options.destructivePre) {
resolveDestructiveChanges(options.destructivePre, DestructiveChangesType.PRE);
}
if (options.destructivePost) {
resolveDestructiveChanges(options.destructivePost, DestructiveChangesType.POST);
}

src/collections/componentSet.ts Show resolved Hide resolved
src/collections/componentSet.ts Show resolved Hide resolved
src/collections/componentSet.ts Show resolved Hide resolved
const destructiveManifestPath = join(packagePath, manifestFileName);
tasks.push(promises.writeFile(destructiveManifestPath, destructiveManifestContents));
const destructiveChangesTypes = cs.getTypesOfDestructiveChanges();
if (destructiveChangesTypes) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be an empty array, which is truthy so we should instead do if (destructiveChangesTypes.length)

src/convert/metadataConverter.ts Show resolved Hide resolved
@salesforce-cla
Copy link

Thanks for the contribution! Unfortunately we can't verify the commit author(s): William Ruemmele <w***@s***.com>. One possible solution is to add that email to your GitHub account. Alternatively you can change your commits to another email and force push the change. After getting your commits associated with your GitHub account, refresh the status of this Pull Request.

@WillieRuemmele WillieRuemmele merged commit 0f67112 into main Oct 21, 2021
@WillieRuemmele WillieRuemmele deleted the wr/destructiveChanges branch October 21, 2021 14:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants