From 1f0d1ff3f37849216fb52563d6e62d8e360ae0a4 Mon Sep 17 00:00:00 2001
From: Kelly Mears <developers@tinypixel.dev>
Date: Fri, 6 May 2022 11:13:35 -0700
Subject: [PATCH 1/4] add multi-sync script

---
 multi-sync.sh | 207 ++++++++++++++++++++++++++++++++++++++++++++++++++
 sync.json     |  15 ++++
 2 files changed, 222 insertions(+)
 create mode 100644 multi-sync.sh
 create mode 100644 sync.json

diff --git a/multi-sync.sh b/multi-sync.sh
new file mode 100644
index 0000000..a40f592
--- /dev/null
+++ b/multi-sync.sh
@@ -0,0 +1,207 @@
+#!/bin/bash
+
+# Syncing Trellis & Bedrock-based WordPress environments with WP-CLI aliases
+# Version 1.2.0
+# Copyright (c) Ben Word
+
+# Requires: `jq` and new-ish bash (> 4)
+# MacOS users:
+#   > `brew install jq bash`
+#   > `source ~/.zshrc`
+
+JSON_MAPPING="./sync.json"
+
+function connection() {
+  echo $(jq -r ".connection | .$1" $JSON_MAPPING)
+}
+
+function site() {
+  echo $(jq -r ".sites | .[0] | .$1" $JSON_MAPPING)
+}
+
+function env() {
+  echo $(jq -r ".sites | .[$1] | .$2 | .$3" $JSON_MAPPING)
+}
+
+function replace() {
+  from=$1
+  to=$2
+  use_alias=$3
+  id=0
+  for _x in $(jq -c ".sites | .[]" $JSON_MAPPING); do
+    if [ "$use_alias" = true ]; then
+      echo "[@${to}] $(env $id $from) => $(env $id $to)";
+      wp search-replace "@${2}" "$(env $id $from)" "$(env $id $to)" --all-tables-with-prefix --network;
+    else
+      echo "[local] $(env $id $from) => $(env $id $to)";
+      wp search-replace "$(env $id $from)" "$(env $id $to)" --all-tables-with-prefix --network;
+    fi
+
+    ((id++));
+  done
+}
+
+uploads=$(jq -r ".uploads" $JSON_MAPPING)
+
+LOCAL=false
+SKIP_DB=false
+SKIP_ASSETS=false
+POSITIONAL_ARGS=()
+
+while [[ $# -gt 0 ]]; do
+  case $1 in
+    --skip-db)
+      SKIP_DB=true
+      shift
+      ;;
+    --skip-assets)
+      SKIP_ASSETS=true
+      shift
+      ;;
+    --local)
+      LOCAL=true
+      shift
+      ;;
+    --*)
+      echo "Unknown option $1"
+      exit 1
+      ;;
+    *)
+      POSITIONAL_ARGS+=("$1")
+      shift
+      ;;
+  esac
+done
+
+set -- "${POSITIONAL_ARGS[@]}"
+
+if [ $# != 2 ]
+then
+  echo "Usage: $0 [[--skip-db] [--skip-assets] [--local]] [ENV_FROM] [ENV_TO]"
+exit;
+fi
+
+FROM=$1
+TO=$2
+
+bold=$(tput bold)
+normal=$(tput sgr0)
+
+case "$1-$2" in
+  production-development) DIR="down ⬇️ "          FROMSITE=$(site production); FROMDIR=$(connection production); TOSITE=$(site development);  TODIR=$uploads; ;;
+  staging-development)    DIR="down ⬇️ "          FROMSITE=$(site staging); FROMDIR=$(connection staging); TOSITE=$(site development);  TODIR=$uploads; ;;
+  development-production) DIR="up ⬆️ "            FROMSITE=$(site development);  FROMDIR=$uploads;  TOSITE=$(site production); TODIR=$(connection production); ;;
+  development-staging)    DIR="up ⬆️ "            FROMSITE=$(site development);  FROMDIR=$uploads;  TOSITE=$(site staging); TODIR=$(connection staging); ;;
+  production-staging)     DIR="horizontally ↔️ ";  FROMSITE=$(site production); FROMDIR=$(connection production); TOSITE=$(site staging); TODIR=$(connection staging); ;;
+  staging-production)     DIR="horizontally ↔️ ";  FROMSITE=$(site staging); FROMDIR=$(connection staging); TOSITE=$(site production); TODIR=$(connection production); ;;
+  *) echo "usage: $0 [[--skip-db] [--skip-assets] [--local]] production development | staging development | development staging | development production | staging production | production staging" && exit 1 ;;
+esac
+
+if [ "$SKIP_DB" = false ]
+then
+  DB_MESSAGE=" - ${bold}reset the $TO database${normal} ($TOSITE)"
+fi
+
+if [ "$SKIP_ASSETS" = false ]
+then
+  ASSETS_MESSAGE=" - sync ${bold}$DIR${normal} from $FROM ($FROMSITE)?"
+fi
+
+if [ "$SKIP_DB" = true ] && [ "$SKIP_ASSETS" = true ]
+then
+  echo "Nothing to synchronize."
+  exit;
+fi
+
+echo
+echo "Would you really like to "
+echo $DB_MESSAGE
+echo $ASSETS_MESSAGE
+read -r -p " [y/N] " response
+
+if [[ "$response" =~ ^([yY][eE][sS]|[yY])$ ]]; then
+  # Change to site directory
+  cd ../ &&
+  echo
+
+  # Make sure both environments are available before we continue
+  availfrom() {
+    local AVAILFROM
+
+    if [[ "$LOCAL" = true && $FROM == "development" ]]; then
+      AVAILFROM=$(wp option get home 2>&1)
+    else
+      AVAILFROM=$(wp "@$FROM" option get home 2>&1)
+    fi
+    if [[ $AVAILFROM == *"Error"* ]]; then
+      echo "❌  Unable to connect to $FROM"
+      exit 1
+    else
+      echo "✅  Able to connect to $FROM"
+    fi
+  };
+  availfrom
+
+  availto() {
+    local AVAILTO
+    if [[ "$LOCAL" = true && $TO == "development" ]]; then
+      AVAILTO=$(wp option get home 2>&1)
+    else
+      AVAILTO=$(wp "@$TO" option get home 2>&1)
+    fi
+
+    if [[ $AVAILTO == *"Error"* ]]; then
+      echo "❌  Unable to connect to $TO $AVAILTO"
+      exit 1
+    else
+      echo "✅  Able to connect to $TO"
+    fi
+  };
+  availto
+
+  if [ "$SKIP_DB" = false ]
+  then
+  echo "Syncing database..."
+    # Export/import database, run search & replace
+    if [[ "$LOCAL" = true && $TO == "development" ]]; then
+      wp db export --default-character-set=utf8mb4 &&
+      wp db reset --yes &&
+      wp "@$FROM" db export --default-character-set=utf8mb4 - | wp db import - &&
+      replace $FROM $TO
+    elif [[ "$LOCAL" = true && $FROM == "development" ]]; then
+      wp "@$TO" db export --default-character-set=utf8mb4 &&
+      wp "@$TO" db reset --yes &&
+      wp db export --default-character-set=utf8mb4 - | wp "@$TO" db import - &&
+      replace $FROM $TO true
+    else
+      wp "@$TO" db export --default-character-set=utf8mb4 &&
+      wp "@$TO" db reset --yes &&
+      wp "@$FROM" db export --default-character-set=utf8mb4 - | wp "@$TO" db import - &&
+      replace $FROM $TO true
+    fi
+  fi
+
+  if [ "$SKIP_ASSETS" = false ]
+  then
+  echo "Syncing assets..."
+    # Sync uploads directory
+    $(chmod -R 755 "$uploads") &&
+    if [[ $DIR == "horizontally"* ]]; then
+      [[ $FROMDIR =~ ^(.*): ]] && FROMHOST=${BASH_REMATCH[1]}
+      [[ $FROMDIR =~ ^(.*):(.*)$ ]] && FROMDIR=${BASH_REMATCH[2]}
+      [[ $TODIR =~ ^(.*): ]] && TOHOST=${BASH_REMATCH[1]}
+      [[ $TODIR =~ ^(.*):(.*)$ ]] && TODIR=${BASH_REMATCH[2]}
+
+      ssh -o ForwardAgent=yes $FROMHOST "rsync -aze 'ssh -o StrictHostKeyChecking=no' --progress $FROMDIR $TOHOST:$TODIR"
+    else
+      rsync -az --progress "$FROMDIR" "$TODIR"
+    fi
+  fi
+
+  # Slack notification when sync direction is up or horizontal
+  # if [[ $DIR != "down"* ]]; then
+  #   USER="$(git config user.name)"
+  #   curl -X POST -H "Content-type: application/json" --data "{\"attachments\":[{\"fallback\": \"\",\"color\":\"#36a64f\",\"text\":\"🔄 Sync from ${FROMSITE} to ${TOSITE} by ${USER} complete \"}],\"channel\":\"#site\"}" https://hooks.slack.com/services/xx/xx/xx
+  # fi
+  echo -e "\n🔄  Sync from $FROM to $TO complete.\n\n    ${bold}$TOSITE${normal}\n"
+fi
diff --git a/sync.json b/sync.json
new file mode 100644
index 0000000..ae150cc
--- /dev/null
+++ b/sync.json
@@ -0,0 +1,15 @@
+{
+  "uploads": "web/app/uploads/",
+  "connection": {
+    "development": "web@example.com:/srv/www/example.com/shared/uploads/",
+    "staging": "web@staging.example.com:/srv/www/example.com/shared/uploads/",
+    "production": "web@example.com:/srv/www/example.com/shared/uploads/"
+  },
+  "sites": [
+    {
+      "production": "https://example.com",
+      "staging": "https://staging.example.com",
+      "development": "http://example.com"
+    }
+  ]
+}

From 18545f0d8aec96b0bbad2bc330f61a08a69bfc2f Mon Sep 17 00:00:00 2001
From: Kelly Mears <developers@tinypixel.dev>
Date: Fri, 6 May 2022 14:17:14 -0700
Subject: [PATCH 2/4] improve/fix

---
 multi-sync.sh | 45 +++++++++++++++++++++++----------------------
 sync.json     | 11 ++++++++---
 2 files changed, 31 insertions(+), 25 deletions(-)

diff --git a/multi-sync.sh b/multi-sync.sh
index a40f592..a3b51a5 100644
--- a/multi-sync.sh
+++ b/multi-sync.sh
@@ -9,40 +9,43 @@
 #   > `brew install jq bash`
 #   > `source ~/.zshrc`
 
-JSON_MAPPING="./sync.json"
+basedir="$(dirname $(realpath ../composer.json))"
+jsonpath="$basedir/scripts/sync.json"
+uploads="$basedir/$(jq -r '.uploads' $jsonpath)"
 
 function connection() {
-  echo $(jq -r ".connection | .$1" $JSON_MAPPING)
+  echo $(jq -r ".connection | .$1" $jsonpath)
 }
 
 function site() {
-  echo $(jq -r ".sites | .[0] | .$1" $JSON_MAPPING)
+  echo $(jq -r ".sites | .[0] | .$1" $jsonpath)
 }
 
 function env() {
-  echo $(jq -r ".sites | .[$1] | .$2 | .$3" $JSON_MAPPING)
+  echo $(jq -r ".sites | .[$1] | .$2 | .$3" $jsonpath)
+}
+
+function protocol() {
+  result="$(jq -r ".secure | .$1" $jsonpath)"
+  if [[ "$result" == "true" ]]; then
+    echo "https://"
+  else
+    echo "http://"
+  fi
 }
 
 function replace() {
   from=$1
   to=$2
-  use_alias=$3
   id=0
-  for _x in $(jq -c ".sites | .[]" $JSON_MAPPING); do
-    if [ "$use_alias" = true ]; then
-      echo "[@${to}] $(env $id $from) => $(env $id $to)";
-      wp search-replace "@${2}" "$(env $id $from)" "$(env $id $to)" --all-tables-with-prefix --network;
-    else
-      echo "[local] $(env $id $from) => $(env $id $to)";
-      wp search-replace "$(env $id $from)" "$(env $id $to)" --all-tables-with-prefix --network;
-    fi
-
+  for _x in $(jq -c ".sites | .[]" $jsonpath); do
+    echo "[@${to}] $(env $id $from) => $(env $id $to)";
+    wp "@${to}" search-replace "$(env $id $from)" "$(env $id $to)" --network;
+    wp "@${to}" search-replace "$(protocol $from)$(env $id $to)" "$(protocol $to)$(env $id $to)" --network;
     ((id++));
   done
 }
 
-uploads=$(jq -r ".uploads" $JSON_MAPPING)
-
 LOCAL=false
 SKIP_DB=false
 SKIP_ASSETS=false
@@ -166,18 +169,16 @@ if [[ "$response" =~ ^([yY][eE][sS]|[yY])$ ]]; then
     if [[ "$LOCAL" = true && $TO == "development" ]]; then
       wp db export --default-character-set=utf8mb4 &&
       wp db reset --yes &&
-      wp "@$FROM" db export --default-character-set=utf8mb4 - | wp db import - &&
+      wp "@$FROM" db export --default-character-set=utf8mb4 - | wp db import -
       replace $FROM $TO
     elif [[ "$LOCAL" = true && $FROM == "development" ]]; then
       wp "@$TO" db export --default-character-set=utf8mb4 &&
-      wp "@$TO" db reset --yes &&
       wp db export --default-character-set=utf8mb4 - | wp "@$TO" db import - &&
-      replace $FROM $TO true
+      replace $FROM $TO
     else
       wp "@$TO" db export --default-character-set=utf8mb4 &&
-      wp "@$TO" db reset --yes &&
       wp "@$FROM" db export --default-character-set=utf8mb4 - | wp "@$TO" db import - &&
-      replace $FROM $TO true
+      replace $FROM $TO
     fi
   fi
 
@@ -185,7 +186,7 @@ if [[ "$response" =~ ^([yY][eE][sS]|[yY])$ ]]; then
   then
   echo "Syncing assets..."
     # Sync uploads directory
-    $(chmod -R 755 "$uploads") &&
+    $(chmod -R 755 $uploads) &&
     if [[ $DIR == "horizontally"* ]]; then
       [[ $FROMDIR =~ ^(.*): ]] && FROMHOST=${BASH_REMATCH[1]}
       [[ $FROMDIR =~ ^(.*):(.*)$ ]] && FROMDIR=${BASH_REMATCH[2]}
diff --git a/sync.json b/sync.json
index ae150cc..eaade29 100644
--- a/sync.json
+++ b/sync.json
@@ -5,11 +5,16 @@
     "staging": "web@staging.example.com:/srv/www/example.com/shared/uploads/",
     "production": "web@example.com:/srv/www/example.com/shared/uploads/"
   },
+  "secure": {
+    "development": false,
+    "staging": true,
+    "production": true
+  },
   "sites": [
     {
-      "production": "https://example.com",
-      "staging": "https://staging.example.com",
-      "development": "http://example.com"
+      "production": "example.com",
+      "staging": "staging.example.com",
+      "development": "example.com"
     }
   ]
 }

From b63b2cdb86abcd898184b7d2ddd05cc2f0c31f6d Mon Sep 17 00:00:00 2001
From: Kelly Mears <developers@tinypixel.dev>
Date: Fri, 6 May 2022 14:17:58 -0700
Subject: [PATCH 3/4] support local

---
 multi-sync.sh | 23 ++++++++++++++++++++---
 1 file changed, 20 insertions(+), 3 deletions(-)

diff --git a/multi-sync.sh b/multi-sync.sh
index a3b51a5..b9a1cc9 100644
--- a/multi-sync.sh
+++ b/multi-sync.sh
@@ -37,11 +37,26 @@ function protocol() {
 function replace() {
   from=$1
   to=$2
+  local=$3
   id=0
   for _x in $(jq -c ".sites | .[]" $jsonpath); do
     echo "[@${to}] $(env $id $from) => $(env $id $to)";
-    wp "@${to}" search-replace "$(env $id $from)" "$(env $id $to)" --network;
-    wp "@${to}" search-replace "$(protocol $from)$(env $id $to)" "$(protocol $to)$(env $id $to)" --network;
+    echo "[@${to}] $(protocol $from)$(env $id $to) => $(protocol $to)$(env $id $to)";
+
+    if [[ "$local" == "true" ]]; then
+      wp search-replace "$(env $id $from)" "$(env $id $to)" --network;
+      if [[ "$(protocol $from)$(env $id $to)" != "$(protocol $from)$(env $id $to)" ]]
+      then
+        wp search-replace "$(protocol $from)$(env $id $to)" "$(protocol $to)$(env $id $to)" --network;
+      fi
+    else
+      wp "@${to}" search-replace "$(env $id $from)" "$(env $id $to)" --network;
+      if [[ "$(protocol $from)$(env $id $to)" != "$(protocol $from)$(env $id $to)" ]]
+      then
+        wp "@${to}" search-replace "$(protocol $from)$(env $id $to)" "$(protocol $to)$(env $id $to)" --network;
+      fi
+    fi;
+
     ((id++));
   done
 }
@@ -170,13 +185,15 @@ if [[ "$response" =~ ^([yY][eE][sS]|[yY])$ ]]; then
       wp db export --default-character-set=utf8mb4 &&
       wp db reset --yes &&
       wp "@$FROM" db export --default-character-set=utf8mb4 - | wp db import -
-      replace $FROM $TO
+      replace $FROM $TO true
     elif [[ "$LOCAL" = true && $FROM == "development" ]]; then
       wp "@$TO" db export --default-character-set=utf8mb4 &&
+      wp "@$TO" db reset --yes &&
       wp db export --default-character-set=utf8mb4 - | wp "@$TO" db import - &&
       replace $FROM $TO
     else
       wp "@$TO" db export --default-character-set=utf8mb4 &&
+      wp "@$TO" db reset --yes &&
       wp "@$FROM" db export --default-character-set=utf8mb4 - | wp "@$TO" db import - &&
       replace $FROM $TO
     fi

From 2ea1a79b6660a87e33e65a2729739b087ca6fbbf Mon Sep 17 00:00:00 2001
From: Kelly Mears <developers@tinypixel.dev>
Date: Fri, 6 May 2022 14:19:59 -0700
Subject: [PATCH 4/4] protocol search-replace conditional

---
 multi-sync.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/multi-sync.sh b/multi-sync.sh
index b9a1cc9..f8033df 100644
--- a/multi-sync.sh
+++ b/multi-sync.sh
@@ -45,13 +45,13 @@ function replace() {
 
     if [[ "$local" == "true" ]]; then
       wp search-replace "$(env $id $from)" "$(env $id $to)" --network;
-      if [[ "$(protocol $from)$(env $id $to)" != "$(protocol $from)$(env $id $to)" ]]
+      if [[ "$(protocol $from)$(env $id $to)" != "$(protocol $to)$(env $id $to)" ]]
       then
         wp search-replace "$(protocol $from)$(env $id $to)" "$(protocol $to)$(env $id $to)" --network;
       fi
     else
       wp "@${to}" search-replace "$(env $id $from)" "$(env $id $to)" --network;
-      if [[ "$(protocol $from)$(env $id $to)" != "$(protocol $from)$(env $id $to)" ]]
+      if [[ "$(protocol $from)$(env $id $to)" != "$(protocol $to)$(env $id $to)" ]]
       then
         wp "@${to}" search-replace "$(protocol $from)$(env $id $to)" "$(protocol $to)$(env $id $to)" --network;
       fi