- Removed long options from input parsing in all bash scripts - Updated all help texts to show only two-character options - Fixed error messages to reference short options only - All scripts now reject long options like --help, --verbose, --target-org - Maintained internal use of long sf CLI commands (e.g., --target-org passed to sf) - Updated README.md documentation to reflect two-character scheme only - Scripts affected: sf-retrieve, sf-test-run, sf-data-import, sf-data-export - PowerShell scripts already used correct two-character parameter scheme - All wrapper scripts now have consistent user interface This ensures strict consistency in the two-character option scheme while maintaining backward compatibility for the sf CLI commands themselves.
277 lines
6.9 KiB
Bash
Executable File
277 lines
6.9 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 Org alias or username to retrieve from (required)
|
|
-tp Comma-separated metadata types (ApexClass,CustomObject,Flow,etc.)
|
|
-nm Comma-separated component names (optional, works with -tp)
|
|
-mn Path to manifest file (package.xml)
|
|
-pk Package name to retrieve
|
|
-dr Target directory for retrieved metadata (default: force-app)
|
|
-hp 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)
|
|
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)
|
|
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)
|
|
if [[ -n "${2:-}" && ! "$2" =~ ^- ]]; then
|
|
NAMES="$2"
|
|
shift 2
|
|
else
|
|
echo "Error: -nm requires a names argument" >&2
|
|
show_help
|
|
exit 1
|
|
fi
|
|
;;
|
|
-mn)
|
|
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)
|
|
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)
|
|
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)
|
|
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
|
|
# Trim whitespace using parameter expansion instead of xargs
|
|
TYPE="${TYPE#"${TYPE%%[![:space:]]*}"}"
|
|
TYPE="${TYPE%"${TYPE##*[![:space:]]}"}"
|
|
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
|
|
# Trim whitespace using parameter expansion instead of xargs
|
|
NAME="${NAME#"${NAME%%[![:space:]]*}"}"
|
|
NAME="${NAME%"${NAME##*[![:space:]]}"}"
|
|
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
|