Oh my god. It's full of code!

Posts tagged “sfdx

Salesforce Destructive Changes Generator/Deployer

So I was going through some of my old projects and getting them stored in github like some kind of real developer and stumbled across this one which I figured might be worth a post. This is a utility for building a destructiveChanges.xml file that can be deployed to multiple orgs automatically. It uses an execute anonymous script to query your org in whatever way you like to generate a list of metadata to delete and then can deploy it for you to all those orgs. Again I’ll explain a little about why this exists and maybe you’ll find a use for it.

Problem: We have multiple orgs where through testing/development and users being users we have lots of unwanted list views and other types of metadata. We want to remove them from multiple orgs without having to do it manually and refresh sandboxes etc. We also wanted to do this once or twice a week (long story, just trust me on this).

Solution: Write an apex script that can query for the metadata (yes, unfortunately the metadata has to be queryable for this to work), generate a destructive changes file and deploy it to a list of orgs. Then use a nodeJS application to deploy those files to each org automatically.

Now this is more of a developer resource than a full application. It comes with some sample code to show how to use it, but for it to be really useful you are going to have to do some coding of your own most likely (pretty much just writing queries to feed into the sObjectListToStringList function). You’ll need nodeJs and SFDX setup for this to work.

The buildPackage.apex file is where you’ll be adding logic to actually generate the destructive changes file. In the buildPackage function there is a map called packageContents, that is where you will need to add the metadata you want to remove with the key being the metadata type and the value being a list of developerNames of that object type. You’ll write functions to create those queries and then store those values in that map before it is passed to the buildPackageString() function.

The buld_and_deploy_changes.js file is where you can control the behavior such as ignoreDeployErrors for one org and continuing to the next, doDeployment dictates if any kind of deployment should be attempted (validate only or actually deploy) or just generate the XML files, checkOnlyMode so changes are only validated but not deployed (true by default to stop you accidentally deleting stuff while testing), and setting the list of usernames to use as org credentials. Of course for any org you want this to run against you’ll need to have authorized it via SFDX.

Once the script has been run in the destructiveChanges folder a new folder will be created for each org with the destructiveChanges.xml file saved there. After the files are created the automatic deployment will run if you’ve set doDeployment to true and push those changes into your orgs.

You can check it out over at https://github.com/Kenji776/SFDestructiveChangesGenerator and let me know if you have any questions or suggestions on how to improve. Just fair warning I take absolutly no responsibility for the results of using this. It’s up to you to ensure the destructiveChanges files look okay before deploying them so absolutely use the doDeployment=false and/or checkOnlyMode=true until you are sure things look like you want.


Salesforce Apex Script Loader

I’m working on a new tool that may or may not be useful but I’ll explain a little about why it came to exist, what it does and you can decide if it has any value for you or not.

Problem: I have a task that I need to do in our production org each day. I must find any cases that have a certain status, change the status, then change them back to re-trigger a back end process. This is obviously a menial task but can be rather annoying to do if there are more than a few records.

Solution: Write an execute anonymous script to find the cases, modify them as needed and save them back. Easy enough (it’s our prod org and writing a new batch/schedulable class to handle this temporary issue would never fly).

Next Problem: I don’t really like having to log in to the org, open the dev console and run the script. Even that seems like it takes too much time and I actually have to remember to do it. I’d rather just have it all handled automatically.

Next Solution: SFDX allows you to run saved script files against an org you have authenticated against. I can write a simple shell script that can be scheduled and calls my script. The script can handle the work and send me an email with the results incase I’m asked how the queue was that day.

Next Problem: I like to over engineer things when I’m having fun and couldn’t leave well enough alone.

Next Solution: I write an over complicated yet flexible node JS wrapper that I’m calling the Apex Script Loader that is meant to allow numerous different pre saved scripts with their own configurations and even injectable variables for some reason.

You: “Wait, why?”

Me: “Because it was fun and I’ve haven’t had much interesting work to do recently okay?”

So a bit more about how this works. Say you have a script you need to run daily and want to just run it from your desktop instead of needing a scheduled class. Here is what you could do.

  1. Ensure you have Node installed and SFDX installed and your desired org authorized.
  2. Download my Apex Script Loader
  3. Make a new folder to contain your script and the config file.
  4. Write your Apex script and save it in that folder
  5. Copy the sample config file and change your username and other details as needed.
  6. Test that it runs by simply running ‘node ApexScriptLoader.js YourFolderNameHere’
  7. Watch it do it’s thing.
  8. Use the task scheduler on your desktop to run the command whenever you like.
  9. Say “huh, that’s neat” then promptly forget it exists because it’s hardly useful.

But wait you say –

“My script needs to pull in data from some external source and that execute anonymous script can’t access anything on my local file system! Furthermore there is no way to pass data into the script so it’s basically living in a black box aside from what it can query from Salesforce!”

Chill bruh. That’s where my insane over thinking comes in handy. I’ve added a ‘variable injection’ feature that lets you provide as many variables as you like in JSON format via a ‘variables.json’ file (name configurable in the config file). In that file you can provide as many key/value pairs as you like and when the Script Loader runs it will process those and inject them into your Apex script making them available in the runTimeVars variable. So now whatever other processes you have simple need to modify that file adding in their values and your script can access them. Pretty cool huh? I figure later on I’ll probably add the ability to read from multiple files so if you have multiple systems all providing values they aren’t fighting over the file but we’ll see if anyone actually even needs that.

Sample output of the script loader (after that it started printing actual org data so I cut it off)
Sample Configuration File so you can see what variables you can configure
What the variables.json file looks like. You can add as many as you like and of any type supported in JSON
Here you can see what the actual Apex script looks like after the variables have been injected at run time.

If you want to check it out, you can grab it over at https://github.com/Kenji776/ApexScriptLoader

The included sample script does not modify your org in any way, I’ve commented out the update statements so you can run it without fear. It will send you an email when it’s done so you know it ran (if you have it scheduled on a dumb terminal somewhere). Also, I’ve only included a bat file for invoking the script, but it’s literally 3 lines so I’m pretty sure you can write your own version for linux/mac/smart fridge/whatever if you need.

I literally just wrote this today in like the last few hours so there are probably some bugs and less than optimal approaches but I can feel myself already losing interest so I figured I should probably post something before this ends up in the heaps of interesting projects that never see the light of day. Let me know if you have questions are can think of any handy features.

Anyway, hope this helps someone. Till next time.

-Kenji