- Replace single-character options with memorable two-character alternatives - Based on syllable mapping: -to (target-org), -qy (query), -fm (format), etc. - Updated all bash and PowerShell scripts with consistent options - Added comprehensive documentation and examples to README.md - Maintains backward compatibility with long options - More intuitive and self-documenting than traditional CLI options
245 lines
6.9 KiB
PowerShell
245 lines
6.9 KiB
PowerShell
#!/usr/bin/env pwsh
|
|
|
|
<#
|
|
.SYNOPSIS
|
|
Anonymous Apex execution wrapper for Salesforce CLI
|
|
|
|
.DESCRIPTION
|
|
A user-friendly wrapper around 'sf apex run' that simplifies executing
|
|
anonymous Apex code from files or inline strings with better formatting
|
|
and error handling.
|
|
|
|
.PARAMETER File
|
|
Path to Apex file to execute
|
|
|
|
.PARAMETER Code
|
|
Inline Apex code to execute (alternative to -File)
|
|
|
|
.PARAMETER o
|
|
Target org username or alias (uses default if not specified)
|
|
|
|
.PARAMETER Verbose
|
|
Enable verbose output showing execution details
|
|
|
|
.PARAMETER Help
|
|
Show this help message
|
|
|
|
.EXAMPLE
|
|
.\sf-apex-run.ps1 -File "scripts/setup.apex"
|
|
.\sf-apex-run.ps1 -Code "System.debug('Hello World');"
|
|
.\sf-apex-run.ps1 -File "test.apex" -o "sandbox"
|
|
.\sf-apex-run.ps1 -Code "Database.insert(new Account(Name='Test'));" -Verbose
|
|
|
|
.NOTES
|
|
This script automatically checks for Salesforce CLI installation and runs
|
|
diagnostics if the CLI is not found.
|
|
#>
|
|
|
|
param(
|
|
[Parameter(ParameterSetName="File")]
|
|
[string]$File,
|
|
|
|
[Parameter(ParameterSetName="Code")]
|
|
[string]$Code,
|
|
|
|
[string]$o,
|
|
[switch]$Verbose,
|
|
[switch]$Help
|
|
)
|
|
|
|
# Show help if requested
|
|
if ($Help) {
|
|
Get-Help $MyInvocation.MyCommand.Path -Detailed
|
|
exit 0
|
|
}
|
|
|
|
# Function to check if Salesforce CLI is installed
|
|
function Test-SalesforceCLI {
|
|
try {
|
|
$null = Get-Command sf -ErrorAction Stop
|
|
return $true
|
|
} catch {
|
|
return $false
|
|
}
|
|
}
|
|
|
|
# Function to run sf-check diagnostics
|
|
function Invoke-SalesforceCheck {
|
|
$checkScript = if (Test-Path "sf-check.ps1") {
|
|
".\sf-check.ps1"
|
|
} elseif (Test-Path "sf-check.sh") {
|
|
"bash sf-check.sh"
|
|
} else {
|
|
$null
|
|
}
|
|
|
|
if ($checkScript) {
|
|
Write-Host "Running Salesforce CLI diagnostics..." -ForegroundColor Yellow
|
|
Invoke-Expression $checkScript
|
|
} else {
|
|
Write-Host "Salesforce CLI not found and no diagnostic script available." -ForegroundColor Red
|
|
Write-Host "Please install the Salesforce CLI: https://developer.salesforce.com/tools/salesforcecli" -ForegroundColor Red
|
|
}
|
|
}
|
|
|
|
# Function to display code preview
|
|
function Show-CodePreview {
|
|
param([string]$CodeContent, [string]$Source)
|
|
|
|
Write-Host "📝 Apex Code ($Source):" -ForegroundColor Yellow
|
|
Write-Host "----------------------------------------" -ForegroundColor Gray
|
|
|
|
# Show first few lines of code for preview
|
|
$lines = $CodeContent -split "`n"
|
|
$previewLines = if ($lines.Count -gt 10) {
|
|
$lines[0..9] + @("... (truncated, $($lines.Count - 10) more lines)")
|
|
} else {
|
|
$lines
|
|
}
|
|
|
|
foreach ($line in $previewLines) {
|
|
Write-Host " $line" -ForegroundColor White
|
|
}
|
|
Write-Host "----------------------------------------" -ForegroundColor Gray
|
|
}
|
|
|
|
# Silently check for Salesforce CLI
|
|
if (-not (Test-SalesforceCLI)) {
|
|
Invoke-SalesforceCheck
|
|
exit 1
|
|
}
|
|
|
|
# Validate that either file or code is provided
|
|
if (-not $File -and -not $Code) {
|
|
Write-Host "Error: Must specify either -File or -Code parameter" -ForegroundColor Red
|
|
Write-Host ""
|
|
Write-Host "Usage examples:" -ForegroundColor Yellow
|
|
Write-Host " .\sf-apex-run.ps1 -File `"scripts/setup.apex`"" -ForegroundColor Gray
|
|
Write-Host " .\sf-apex-run.ps1 -Code `"System.debug('Hello World');`"" -ForegroundColor Gray
|
|
Write-Host ""
|
|
Write-Host "Use -Help for detailed usage information." -ForegroundColor Yellow
|
|
exit 1
|
|
}
|
|
|
|
# Validate that both file and code aren't provided
|
|
if ($File -and $Code) {
|
|
Write-Host "Error: Cannot specify both -File and -Code parameters" -ForegroundColor Red
|
|
exit 1
|
|
}
|
|
|
|
# If file is specified, validate it exists and read content
|
|
if ($File) {
|
|
if (-not (Test-Path $File)) {
|
|
Write-Host "Error: Apex file not found: $File" -ForegroundColor Red
|
|
exit 1
|
|
}
|
|
|
|
try {
|
|
$apexContent = Get-Content -Path $File -Raw
|
|
Write-Host "Using Apex file: $File" -ForegroundColor Green
|
|
|
|
if ($Verbose) {
|
|
Show-CodePreview $apexContent "from file: $File"
|
|
}
|
|
} catch {
|
|
Write-Host "Error reading Apex file: $($_.Exception.Message)" -ForegroundColor Red
|
|
exit 1
|
|
}
|
|
} else {
|
|
$apexContent = $Code
|
|
Write-Host "Using inline Apex code" -ForegroundColor Green
|
|
|
|
if ($Verbose) {
|
|
Show-CodePreview $apexContent "inline"
|
|
}
|
|
}
|
|
|
|
# Build the sf command
|
|
$sfArgs = @("apex", "run")
|
|
|
|
# Add target org if specified
|
|
if ($o) {
|
|
$sfArgs += "--target-org"
|
|
$sfArgs += $o
|
|
Write-Host "Target org: $o" -ForegroundColor Cyan
|
|
}
|
|
|
|
# Add verbose flag if requested
|
|
if ($Verbose) {
|
|
$sfArgs += "--verbose"
|
|
}
|
|
|
|
# Display execution info
|
|
Write-Host ""
|
|
Write-Host "🚀 Executing Anonymous Apex" -ForegroundColor Blue
|
|
Write-Host "============================" -ForegroundColor Blue
|
|
|
|
# Create a temporary file for the Apex content if needed
|
|
$tempFile = $null
|
|
if ($Code) {
|
|
$tempFile = [System.IO.Path]::GetTempFileName() + ".apex"
|
|
try {
|
|
Set-Content -Path $tempFile -Value $apexContent -Encoding UTF8
|
|
$sfArgs += "--file"
|
|
$sfArgs += $tempFile
|
|
} catch {
|
|
Write-Host "Error creating temporary file: $($_.Exception.Message)" -ForegroundColor Red
|
|
exit 1
|
|
}
|
|
} else {
|
|
$sfArgs += "--file"
|
|
$sfArgs += $File
|
|
}
|
|
|
|
# Display the command being run (without showing temp file path)
|
|
$displayArgs = $sfArgs -replace [regex]::Escape($tempFile), '<temp-file>'
|
|
Write-Host ""
|
|
Write-Host "Executing: sf $($displayArgs -join ' ')" -ForegroundColor Gray
|
|
Write-Host ""
|
|
|
|
# Execute the command
|
|
try {
|
|
$startTime = Get-Date
|
|
& sf @sfArgs
|
|
$exitCode = $LASTEXITCODE
|
|
$endTime = Get-Date
|
|
$duration = $endTime - $startTime
|
|
|
|
Write-Host ""
|
|
Write-Host "⏱️ Execution completed in $($duration.TotalSeconds.ToString('F2')) seconds" -ForegroundColor Gray
|
|
|
|
if ($exitCode -eq 0) {
|
|
Write-Host ""
|
|
Write-Host "✅ Anonymous Apex executed successfully!" -ForegroundColor Green
|
|
|
|
if ($Verbose) {
|
|
Write-Host "💡 Check the output above for any System.debug() statements" -ForegroundColor Yellow
|
|
}
|
|
} else {
|
|
Write-Host ""
|
|
Write-Host "❌ Apex execution failed with exit code: $exitCode" -ForegroundColor Red
|
|
Write-Host "💡 Check compilation errors or runtime exceptions above" -ForegroundColor Yellow
|
|
|
|
# Clean up temp file before exiting
|
|
if ($tempFile -and (Test-Path $tempFile)) {
|
|
Remove-Item $tempFile -Force -ErrorAction SilentlyContinue
|
|
}
|
|
|
|
exit $exitCode
|
|
}
|
|
} catch {
|
|
Write-Host "Error executing sf command: $($_.Exception.Message)" -ForegroundColor Red
|
|
|
|
# Clean up temp file before exiting
|
|
if ($tempFile -and (Test-Path $tempFile)) {
|
|
Remove-Item $tempFile -Force -ErrorAction SilentlyContinue
|
|
}
|
|
|
|
exit 1
|
|
} finally {
|
|
# Clean up temporary file
|
|
if ($tempFile -and (Test-Path $tempFile)) {
|
|
Remove-Item $tempFile -Force -ErrorAction SilentlyContinue
|
|
}
|
|
}
|