mirror of
https://github.com/forcedotcom/afv-library.git
synced 2026-08-08 16:25:58 +08:00
251 lines
8.5 KiB
Bash
Executable File
251 lines
8.5 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# Detect, create/deploy, and activate Pipeline Management suggestion processing flow
|
|
#
|
|
# Strategy (in order of preference):
|
|
# 1. Check if flow clone already exists (by SourceTemplateId or naming convention)
|
|
# 2. If missing: deploy from pre-retrieved template (assets/pipeline_management_flow.flow-meta.xml)
|
|
# 3. If deploy fails: instruct user to perform Setup UI "Save As" from managed template
|
|
# 4. If exists but inactive: activate via retrieve → transform → deploy
|
|
#
|
|
# The template (assets/) was retrieved from a live org with Pipeline Management enabled.
|
|
# It contains the complete flow logic including sourceTemplate reference, so the deployed
|
|
# flow registers as a proper clone of sales_pipe_mgmt__OppSuggGenSchFlow.
|
|
#
|
|
# Usage: ./create-flow.sh <org-alias>
|
|
|
|
set -euo pipefail
|
|
|
|
# sf CLI can emit ANSI color codes inside --json stdout, breaking jq parsing.
|
|
# 2>/dev/null only strips stderr; these env vars are the reliable fix (see PM notes).
|
|
export NO_COLOR=1
|
|
export FORCE_COLOR=0
|
|
|
|
# Cross-platform sed -i (macOS requires '' arg, GNU does not)
|
|
sed_inplace() {
|
|
if [[ "$OSTYPE" == "darwin"* ]]; then
|
|
sed -i '' "$@"
|
|
else
|
|
sed -i "$@"
|
|
fi
|
|
}
|
|
|
|
ORG_ALIAS="${1:-}"
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
|
|
if [[ -z "$ORG_ALIAS" ]]; then
|
|
echo "Error: Missing org alias"
|
|
echo "Usage: $0 <org-alias>"
|
|
exit 1
|
|
fi
|
|
|
|
echo "Pipeline Management Flow: Detect + Deploy + Activate"
|
|
echo ""
|
|
|
|
TEMPLATE_NAME="sales_pipe_mgmt__OppSuggGenSchFlow"
|
|
FLOW_API_NAME="Process_Field_Update_Suggestions"
|
|
|
|
# --- Detection ---
|
|
echo -n "Checking if flow clone exists... "
|
|
|
|
# Attempt 1: Query by SourceTemplateId (verified field on FlowDefinitionView in API v67.0)
|
|
EXISTING_QUERY=$(sf data query \
|
|
--query "SELECT Id, ApiName, IsActive, SourceTemplateId FROM FlowDefinitionView WHERE SourceTemplateId = '${TEMPLATE_NAME}' AND IsTemplate = false" \
|
|
--target-org "$ORG_ALIAS" \
|
|
--json 2>/dev/null)
|
|
|
|
EXISTING_FLOW=$(echo "$EXISTING_QUERY" | jq -r '.result.records[0].ApiName // empty' 2>/dev/null || echo "")
|
|
IS_ACTIVE=$(echo "$EXISTING_QUERY" | jq -r '.result.records[0].IsActive // empty' 2>/dev/null || echo "")
|
|
|
|
# Attempt 2: Fallback to naming convention match
|
|
if [[ -z "$EXISTING_FLOW" ]]; then
|
|
EXISTING_QUERY=$(sf data query \
|
|
--query "SELECT Id, ApiName, IsActive FROM FlowDefinitionView WHERE ApiName LIKE '%OppSuggGen%' AND IsTemplate = false" \
|
|
--target-org "$ORG_ALIAS" \
|
|
--json 2>/dev/null)
|
|
|
|
EXISTING_FLOW=$(echo "$EXISTING_QUERY" | jq -r '.result.records[0].ApiName // empty' 2>/dev/null || echo "")
|
|
IS_ACTIVE=$(echo "$EXISTING_QUERY" | jq -r '.result.records[0].IsActive // empty' 2>/dev/null || echo "")
|
|
fi
|
|
|
|
# Attempt 3: Check by standard API name
|
|
if [[ -z "$EXISTING_FLOW" ]]; then
|
|
EXISTING_QUERY=$(sf data query \
|
|
--query "SELECT Id, ApiName, IsActive FROM FlowDefinitionView WHERE ApiName = '${FLOW_API_NAME}'" \
|
|
--target-org "$ORG_ALIAS" \
|
|
--json 2>/dev/null)
|
|
|
|
EXISTING_FLOW=$(echo "$EXISTING_QUERY" | jq -r '.result.records[0].ApiName // empty' 2>/dev/null || echo "")
|
|
IS_ACTIVE=$(echo "$EXISTING_QUERY" | jq -r '.result.records[0].IsActive // empty' 2>/dev/null || echo "")
|
|
fi
|
|
|
|
# --- Flow Not Found: Deploy from Template ---
|
|
if [[ -z "$EXISTING_FLOW" ]]; then
|
|
echo "not found"
|
|
echo ""
|
|
|
|
TEMPLATE_FILE="$SCRIPT_DIR/../assets/pipeline_management_flow.flow-meta.xml"
|
|
|
|
if [[ -f "$TEMPLATE_FILE" ]]; then
|
|
echo "Deploying flow from pre-retrieved template..."
|
|
echo " Template: assets/pipeline_management_flow.flow-meta.xml"
|
|
echo " API Name: $FLOW_API_NAME"
|
|
echo ""
|
|
|
|
# Ensure sfdx-project.json exists
|
|
if [[ ! -f "sfdx-project.json" ]]; then
|
|
cat > sfdx-project.json << 'EOF'
|
|
{"packageDirectories": [{"path": "force-app", "default": true}], "sourceApiVersion": "67.0"}
|
|
EOF
|
|
fi
|
|
|
|
FLOW_DIR="force-app/main/default/flows"
|
|
mkdir -p "$FLOW_DIR"
|
|
FLOW_FILE="${FLOW_DIR}/${FLOW_API_NAME}.flow-meta.xml"
|
|
cp "$TEMPLATE_FILE" "$FLOW_FILE"
|
|
|
|
# Update startDate to today
|
|
TODAY=$(date +%Y-%m-%d)
|
|
sed_inplace "s|<startDate>[^<]*</startDate>|<startDate>${TODAY}</startDate>|g" "$FLOW_FILE"
|
|
|
|
echo " Schedule start: $TODAY (daily at 11:55 UTC)"
|
|
echo " Status: Active"
|
|
echo ""
|
|
|
|
# Deploy
|
|
echo " Deploying..."
|
|
DEPLOY_RESULT=$(sf project deploy start --source-dir "$FLOW_FILE" --target-org "$ORG_ALIAS" --json 2>/dev/null || echo '{"status":1}')
|
|
|
|
if echo "$DEPLOY_RESULT" | jq -e '.status == 0' >/dev/null 2>&1; then
|
|
EXISTING_FLOW="$FLOW_API_NAME"
|
|
IS_ACTIVE="true"
|
|
echo " Deploy SUCCEEDED"
|
|
echo ""
|
|
echo "Flow '$FLOW_API_NAME' deployed and activated."
|
|
echo "Suggestions will generate daily at 11:55 UTC."
|
|
else
|
|
DEPLOY_ERR=$(echo "$DEPLOY_RESULT" | jq -r '.result.details.componentFailures[0].problem // .message // "unknown"' 2>/dev/null || echo "unknown")
|
|
echo " Deploy FAILED: $DEPLOY_ERR"
|
|
echo ""
|
|
echo "Falling back to manual Setup UI clone..."
|
|
echo ""
|
|
fi
|
|
fi
|
|
|
|
# If still no flow, guide user through UI
|
|
if [[ -z "$EXISTING_FLOW" ]]; then
|
|
echo "ACTION REQUIRED: Clone the template manually via Setup UI."
|
|
echo ""
|
|
echo " The template flow is in the 'sales_pipe_mgmt' managed namespace."
|
|
echo ""
|
|
echo " Steps:"
|
|
echo " 1. Open Setup -> Flows"
|
|
echo " 2. Find 'Process Field Update Suggestions' (marked with template icon)"
|
|
echo " 3. Open the flow -> click 'Save As'"
|
|
echo " 4. Label: 'Process Field Update Suggestions' -> Save"
|
|
echo " 5. Click 'Activate' on the new flow"
|
|
echo " 6. Re-run this script to verify"
|
|
echo ""
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# --- Flow Found ---
|
|
if [[ -n "$EXISTING_FLOW" ]]; then
|
|
echo "found: $EXISTING_FLOW (active: $IS_ACTIVE)"
|
|
echo ""
|
|
fi
|
|
|
|
# --- Already Active ---
|
|
if [[ "$IS_ACTIVE" == "true" ]]; then
|
|
echo "Flow '$EXISTING_FLOW' is ACTIVE."
|
|
echo "Suggestions will generate on schedule. No action needed."
|
|
echo ""
|
|
echo "Done."
|
|
exit 0
|
|
fi
|
|
|
|
# --- Exists But Inactive: Activate ---
|
|
echo "Flow '$EXISTING_FLOW' exists but is INACTIVE. Activating..."
|
|
echo ""
|
|
|
|
# Ensure sfdx-project.json exists for retrieve/deploy
|
|
if [[ ! -f "sfdx-project.json" ]]; then
|
|
cat > sfdx-project.json << 'EOF'
|
|
{"packageDirectories": [{"path": "force-app", "default": true}], "sourceApiVersion": "67.0"}
|
|
EOF
|
|
fi
|
|
|
|
FLOW_DIR="force-app/main/default/flows"
|
|
mkdir -p "$FLOW_DIR"
|
|
|
|
# Retrieve the CLONE (not the template — the clone is in the org's namespace and IS retrievable)
|
|
echo " Retrieving flow metadata..."
|
|
sf project retrieve start \
|
|
--metadata "Flow:${EXISTING_FLOW}" \
|
|
--target-org "$ORG_ALIAS" \
|
|
--json 2>/dev/null >/dev/null || true
|
|
|
|
FLOW_FILE="${FLOW_DIR}/${EXISTING_FLOW}.flow-meta.xml"
|
|
|
|
if [[ ! -f "$FLOW_FILE" ]]; then
|
|
echo " Warning: Could not retrieve flow file."
|
|
echo " Activate manually: Setup -> Flows -> ${EXISTING_FLOW} -> Activate"
|
|
exit 1
|
|
fi
|
|
|
|
echo " Retrieved successfully."
|
|
|
|
# Transform status to Active
|
|
echo " Setting status to Active..."
|
|
sed_inplace 's|<status>Draft</status>|<status>Active</status>|g' "$FLOW_FILE"
|
|
sed_inplace 's|<status>Obsolete</status>|<status>Active</status>|g' "$FLOW_FILE"
|
|
|
|
# Deploy
|
|
echo " Deploying activated flow..."
|
|
DEPLOY_RESULT=$(sf project deploy start \
|
|
--metadata "Flow:${EXISTING_FLOW}" \
|
|
--target-org "$ORG_ALIAS" \
|
|
--json 2>/dev/null)
|
|
|
|
if echo "$DEPLOY_RESULT" | jq -e '.status == 0' >/dev/null 2>&1; then
|
|
echo " Deployed successfully."
|
|
else
|
|
ERROR_MSG=$(echo "$DEPLOY_RESULT" | jq -r '.message // .result.details.componentFailures[0].problem // "unknown error"' 2>/dev/null || echo "unknown error")
|
|
echo " Warning: Deploy may have failed: $ERROR_MSG"
|
|
echo " Activate manually: Setup -> Flows -> ${EXISTING_FLOW} -> Activate"
|
|
fi
|
|
|
|
echo ""
|
|
|
|
# --- Final Verification ---
|
|
echo "Verifying final state..."
|
|
sleep 2 # Brief propagation wait
|
|
|
|
VERIFY_RESULT=$(sf data query \
|
|
--query "SELECT ApiName, IsActive FROM FlowDefinitionView WHERE ApiName = '${EXISTING_FLOW}'" \
|
|
--target-org "$ORG_ALIAS" \
|
|
--json 2>/dev/null)
|
|
|
|
FINAL_ACTIVE=$(echo "$VERIFY_RESULT" | jq -r '.result.records[0].IsActive // "unknown"' 2>/dev/null || echo "unknown")
|
|
|
|
if [[ "$FINAL_ACTIVE" == "true" ]]; then
|
|
echo " Flow: $EXISTING_FLOW"
|
|
echo " Status: ACTIVE"
|
|
echo ""
|
|
echo "Flow activated successfully. Suggestions will generate on schedule."
|
|
else
|
|
echo " Flow: $EXISTING_FLOW"
|
|
echo " Status: $FINAL_ACTIVE"
|
|
echo ""
|
|
echo " Flow may need manual activation via Setup UI."
|
|
fi
|
|
|
|
echo ""
|
|
echo "Done."
|
|
echo ""
|
|
echo "Next steps:"
|
|
echo " 1. Verify agent is active (./create-agent.sh $ORG_ALIAS)"
|
|
echo " 2. Configure opportunity stages (see references/opportunity-stages.md)"
|
|
echo " 3. Wait for schedule to trigger, or test with manual notes/emails"
|