Files
sf-cli-wrapper/sf-retrieve
reynold f22a46d711 Complete two-character option consistency across remaining scripts
🎯 Final Consistency Implementation:

 Updated Scripts:
  - sf-org-info: -to, -vb, -ls, -hp (fixed array handling + options)
  - sf-check: -vb, -hp (environment verification)
  - sf-apex-run: -to, -fl, -cd, -hp (Apex execution)
  - sf-retrieve: -to, -tp, -nm, -mn, -pk, -dr, -hp (metadata retrieval)
  - sf-test-run: -to, -cn, -sn, -al, -lv, -cv, -wt, -hp (test execution)

🔧 Key Changes:
  - Replaced ALL single-character options with two-character equivalents
  - Updated argument parsing from getopts to manual parsing
  - Fixed help text and error messages to use new options
  - Updated example commands and references

📊 Consistency Status:
  - 12/12 scripts now use uniform two-character options
  - 0/12 scripts have conflicting option styles
  - 100% consistency achieved across entire toolkit

🚀 Benefits Delivered:
  - No more confusion between scripts
  - Predictable and self-documenting options
  - Professional user experience
  - Ready for production deployment
2025-08-28 19:04:07 +08:00

273 lines
6.8 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
show_help() {
cat <<'EOF'
sf-retrieve — wrapper for streamlined metadata retrieval
USAGE:
sf-retrieve -to <ORG_ALIAS> (-tp <TYPES> | -mn <MANIFEST> | -pk <PACKAGE>) [-nm <NAMES>] [-dr <DIR>] [-hp]
OPTIONS:
-to, --target-org Org alias or username to retrieve from (required)
-tp, --types Comma-separated metadata types (ApexClass,CustomObject,Flow,etc.)
-nm, --names Comma-separated component names (optional, works with -tp)
-mn, --manifest Path to manifest file (package.xml)
-pk, --package Package name to retrieve
-dr, --directory Target directory for retrieved metadata (default: force-app)
-hp, --help Show this help
EXAMPLES:
1) Retrieve all Apex classes:
sf-retrieve -to PROD-ORG -tp "ApexClass"
2) Retrieve specific classes:
sf-retrieve -to PROD-ORG -tp "ApexClass" -nm "MyClass,AnotherClass"
3) Retrieve multiple metadata types:
sf-retrieve -to PROD-ORG -tp "ApexClass,CustomObject,Flow"
4) Retrieve using manifest:
sf-retrieve -to PROD-ORG -mn "manifest/package.xml"
5) Retrieve to specific directory:
sf-retrieve -to PROD-ORG -tp "ApexClass" -dr "retrieved-metadata"
6) Retrieve installed package:
sf-retrieve -to PROD-ORG -pk "MyPackage"
COMMON METADATA TYPES:
- ApexClass, ApexTrigger, ApexComponent, ApexPage
- CustomObject, CustomField, CustomTab
- Flow, ProcessBuilder, WorkflowRule
- Layout, Profile, PermissionSet
- StaticResource, ContentAsset
- CustomApplication, CustomLabel
Notes:
- Use -tp with -nm to retrieve specific components of a type
- Use -mn for complex retrievals with manifest files
- Use -pk to retrieve entire packages
- Retrieved metadata will be in source format
EOF
}
# Default values
ORG=""
TYPES=""
NAMES=""
MANIFEST=""
PACKAGE=""
TARGET_DIR="force-app"
if [[ $# -eq 0 ]]; then
show_help
exit 0
fi
# Parse arguments manually for two-character options
while [[ $# -gt 0 ]]; do
case $1 in
-to|--target-org)
if [[ -n "${2:-}" && ! "$2" =~ ^- ]]; then
ORG="$2"
shift 2
else
echo "Error: -to requires a target org argument" >&2
show_help
exit 1
fi
;;
-tp|--types)
if [[ -n "${2:-}" && ! "$2" =~ ^- ]]; then
TYPES="$2"
shift 2
else
echo "Error: -tp requires a metadata types argument" >&2
show_help
exit 1
fi
;;
-nm|--names)
if [[ -n "${2:-}" && ! "$2" =~ ^- ]]; then
NAMES="$2"
shift 2
else
echo "Error: -nm requires a names argument" >&2
show_help
exit 1
fi
;;
-mn|--manifest)
if [[ -n "${2:-}" && ! "$2" =~ ^- ]]; then
MANIFEST="$2"
shift 2
else
echo "Error: -mn requires a manifest file argument" >&2
show_help
exit 1
fi
;;
-pk|--package)
if [[ -n "${2:-}" && ! "$2" =~ ^- ]]; then
PACKAGE="$2"
shift 2
else
echo "Error: -pk requires a package name argument" >&2
show_help
exit 1
fi
;;
-dr|--directory)
if [[ -n "${2:-}" && ! "$2" =~ ^- ]]; then
TARGET_DIR="$2"
shift 2
else
echo "Error: -dr requires a directory argument" >&2
show_help
exit 1
fi
;;
-hp|--help)
show_help
exit 0
;;
-*)
echo "Unknown option: $1" >&2
echo
show_help
exit 1
;;
*)
echo "Unexpected argument: $1" >&2
echo
show_help
exit 1
;;
esac
done
# Validate required parameters
if [[ -z "$ORG" ]]; then
echo "Error: Org (-to) is required." >&2
echo
show_help
exit 1
fi
# Validate that at least one retrieval method is specified
if [[ -z "$TYPES" && -z "$MANIFEST" && -z "$PACKAGE" ]]; then
echo "Error: Must specify -tp (types), -mn (manifest), or -pk (package)." >&2
echo
show_help
exit 1
fi
# Validate that only one retrieval method is used
method_count=0
[[ -n "$TYPES" ]] && ((method_count++))
[[ -n "$MANIFEST" ]] && ((method_count++))
[[ -n "$PACKAGE" ]] && ((method_count++))
if [[ $method_count -gt 1 ]]; then
echo "Error: Cannot use -tp, -mn, and -pk together. Choose one method." >&2
echo
show_help
exit 1
fi
# Validate manifest file exists
if [[ -n "$MANIFEST" && ! -f "$MANIFEST" ]]; then
echo "Error: Manifest file '$MANIFEST' not found." >&2
exit 1
fi
# Silent environment check
if ! command -v sf >/dev/null 2>&1; then
echo "❌ Salesforce CLI (sf) not found!"
echo
echo "Running environment check to help you get started..."
echo
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
if [[ -x "$SCRIPT_DIR/sf-check" ]]; then
"$SCRIPT_DIR/sf-check"
elif command -v sf-check >/dev/null 2>&1; then
sf-check
else
echo "sf-check not found. Please install the Salesforce CLI from:"
echo "https://developer.salesforce.com/tools/sfdxcli"
fi
exit 1
fi
# Build the command
CMD=(sf project retrieve start)
CMD+=(--target-org "$ORG")
# Add retrieval method
if [[ -n "$TYPES" ]]; then
# Split types by comma and add each as separate --metadata parameter
IFS=',' read -ra TYPES_ARR <<< "$TYPES"
for TYPE in "${TYPES_ARR[@]}"; do
TYPE=$(echo "$TYPE" | xargs) # Trim whitespace
if [[ -n "$TYPE" ]]; then
if [[ -n "$NAMES" ]]; then
# If names are specified, add each name for this type
IFS=',' read -ra NAMES_ARR <<< "$NAMES"
for NAME in "${NAMES_ARR[@]}"; do
NAME=$(echo "$NAME" | xargs) # Trim whitespace
if [[ -n "$NAME" ]]; then
CMD+=(--metadata "$TYPE:$NAME")
fi
done
else
# No names specified, retrieve all of this type
CMD+=(--metadata "$TYPE")
fi
fi
done
elif [[ -n "$MANIFEST" ]]; then
CMD+=(--manifest "$MANIFEST")
elif [[ -n "$PACKAGE" ]]; then
CMD+=(--package-name "$PACKAGE")
fi
# Add target directory
CMD+=(--output-dir "$TARGET_DIR")
# Show what we're retrieving
echo "🔄 Retrieving metadata from org '$ORG'..."
if [[ -n "$TYPES" ]]; then
echo " Types: $TYPES"
[[ -n "$NAMES" ]] && echo " Names: $NAMES"
elif [[ -n "$MANIFEST" ]]; then
echo " Manifest: $MANIFEST"
elif [[ -n "$PACKAGE" ]]; then
echo " Package: $PACKAGE"
fi
echo " Target: $TARGET_DIR"
echo
echo ">>> Running: ${CMD[*]}"
echo
if "${CMD[@]}"; then
echo
echo "✅ Metadata retrieved successfully!"
echo "📁 Check the '$TARGET_DIR' directory for retrieved components."
# Show summary of what was retrieved
if command -v find >/dev/null 2>&1 && [[ -d "$TARGET_DIR" ]]; then
echo
echo "📊 Retrieved components summary:"
find "$TARGET_DIR" -type f -name "*.xml" -o -name "*.cls" -o -name "*.trigger" -o -name "*.js" -o -name "*.html" | \
sed 's|.*/||' | sort | uniq -c | sort -nr | head -10
fi
else
echo
echo "❌ Failed to retrieve metadata"
exit 1
fi