DEV Community

Javier Garcia
Javier Garcia

Posted on • Originally published at manzanos-tech-blog.ghost.io

2 2

Automating Salesforce deployments with PowerShell

Recently I've been learning a little bit of PowerShell, initially for the sake of automating some tedious tasks I had to do at work like calling a REST endpoint 10-20 times to populate some DB for testing or simply pipelining some CLI commands.

The thing is, as I got more comfortable with PS, I started to realize the huge amount of things that can be done with scripts which make our day to day easier. The biggest one that came to my mind was Salesforce deployments.

Usually, once we've finished developing a certain feature in Salesforce, we run all tests, pull all our changes from the environment where we were developing (In Salesforce, you develop remotely, not locally), deploy to a staging environment and run again the tests there.

The issue is that that process involves a lot of manual steps. So I decided to try and automate it. For it, I looked into the SFDX CLI and tried to reuse most of its features: an authentication command, the actual command which calls the deployment endpoint, etc.

Eventually, after a few hours, the result was this:

# https://codereview.stackexchange.com/questions/200870/powershell-script-to-deploy-repository-to-salesforce
param([string] $repositoryDirectory, [bool] $isProduction)
# TODO - git integration. Select a branch and check it out for deploy.
# TODO - break stuff into functions and reusable pieces. ¿piping? ¿cmdlets?
# TODO - Allow directory structures?
Write-Host -ForegroundColor green ":: Validating Repository ::"
$srcDirectory = [System.IO.Path]::Combine($repositoryDirectory, "src")
if(![System.IO.File]::Exists([System.IO.Path]::Combine($srcDirectory,"package.xml"))) {
Write-Host -ForegroundColor red "ERROR: package.xml not found in the ./src directory."
exit
}
Write-Host -ForegroundColor green "`n:: Authenticating to Salesforce ::"
if($isProduction) {
sfdx force:auth:web:login -s -r "https://login.salesforce.com"
}
else {
sfdx force:auth:web:login -s -r "https://test.salesforce.com"
}
Write-Host -ForegroundColor green "`n:: Deploying source code ::"
$deployJob = sfdx force:mdapi:deploy -d $srcDirectory -l "RunLocalTests" --json | ConvertFrom-Json
$deployJobId = $deployJob.result.id
$startedTests = $false
do {
$report = sfdx force:mdapi:deploy:report -i $deployJobId --json --verbose 2>&1 | ConvertFrom-Json
if($null -eq $report) {
continue
}
# Deployment progress block.
if($report.result.numberComponentsTotal -ne 0 -and $componentsRemaining -ne 0) {
$deploymentRatio = [Math]::Ceiling(100 * ($report.result.numberComponentsDeployed / $report.result.numberComponentsTotal))
$componentsRemaining = $report.result.numberComponentsTotal - $report.result.numberComponentsDeployed - $report.result.numberComponentsFailed
# If the percentage is not yet 100%, update it.
if($deploymentRatio -le 100) {
Write-Host -NoNewLine "`rComponents deployed: " $deploymentRatio "%"
}
# If the deployment has failed
if($report.result.status -eq "Failed") {
break
}
}
# Write next header.
if(($report.result.numberTestsTotal -ne 0) -and ($startedTests -eq $false)) {
$startedTests = $true
Write-Host -ForegroundColor green "`n`n:: Running tests ::"
}
# Write Test progress
if($report.result.numberTestsTotal -ne 0 -and $testsRemaining -ne 0) {
$testRatio = [Math]::Ceiling((100 * ($report.result.numberTestsCompleted / $report.result.numberTestsTotal)))
$testsRemaining = $report.result.numberTestsTotal - $report.result.numberTestErrors - $report.result.numberTestsCompleted
Write-Host -NoNewLine "`rTests passed: " $testRatio "% | Tests remaining: " $testsRemaining
}
if($testsRemaining -eq 0 -and $report.result.numberTestErrors -gt 0) {
Write-Host -ForegroundColor red "`nERROR: $($report.result.numberTestErrors) tests have failed"
exit
}
} while(($report.result.status -eq "InProgress") -or ($report.result.status -eq "Pending"))
# FAILED DEPLOYMENT ANALYSIS
if($report.result.status -eq "Failed") {
Write-Host -ForegroundColor red "`n`nERROR Deployment Failed!"
$report = sfdx force:mdapi:deploy:report -i $deployJobId --json --verbose 2>&1 | ConvertFrom-Json
foreach($failure in $report.result.details.componentFailures) {
Write-Host -ForegroundColor red "`t - " $failure.problem
}
exit
}
# SUCCESSFUL DEPLOYMENT MESSAGE
Write-Host -ForegroundColor green "`n`n:: Deployment Successful! ::"
view raw deploy.ps1 hosted with ❤ by GitHub

It's a little nifty script which prompts a tab in your default browser so you log into the destination org and pipelines the deployment and the running of tests with real-time status in the console. That I did simply by polling the API.

There are, of course, many things to be improved in the script but, as a starter, it's already saving me a lot of time! :)

Image of Wix Studio

2025: Your year to build apps that sell

Dive into hands-on resources and actionable strategies designed to help you build and sell apps on the Wix App Market.

Get started

Top comments (2)

Collapse
 
alanmbarr profile image
Alan Barr

Powershell is awesome, you might look into named parameters and validations on those parameters saves a lot of headaches. I typically lean toward using Write-Output instead of Write-Host but that might be a personal preference.

Collapse
 
manzanit0 profile image
Javier Garcia

Yeah, thanks for the heads up Alan :)
As for the Write-Host, the main reason to use it is the colors. Since it's mainly a script to be executed by the user from the console, I thought the colors would be nice. But otherwise, just like you said, Write-Output is always better.