mirror of
https://ghproxy.net/https://github.com/CaptainCore/captaincore.git
synced 2026-07-28 13:07:02 +08:00
183 lines
7 KiB
Bash
Executable file
183 lines
7 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
|
|
#
|
|
# Runs themes, plugins and core updates on one or more sites.
|
|
#
|
|
# `captaincore update`
|
|
#
|
|
# [<site>...]
|
|
# One or more sites to update.
|
|
#
|
|
# [@<target>]
|
|
# Target groups of sites like @all @production or @staging. Use `captaincore update @production.updates-on` to target production sites marked for automatic updates.
|
|
#
|
|
# [--exclude-themes=<themes>]
|
|
# Passed onto `wp theme update --exclude=<theme-names>`
|
|
#
|
|
# [--exclude-plugins=<plugins>]
|
|
# Passed onto `wp plugin update --exclude=<theme-names>`
|
|
#
|
|
|
|
if [ ${#@} -ne 1 ]; then
|
|
echo -e "${COLOR_RED}Error:${COLOR_NORMAL} Please specify a <site>."
|
|
fi
|
|
|
|
while read config; do
|
|
if [[ "$config" == "Error:"* ]]; then
|
|
continue
|
|
fi
|
|
declare "$config"
|
|
done <<< "$(captaincore config fetch --captain-id=$CAPTAIN_ID)"
|
|
|
|
site=$1
|
|
|
|
run_command() {
|
|
|
|
# Extract environment
|
|
if [[ "$site" == *"-staging"* ]]; then
|
|
environment=staging
|
|
else
|
|
environment=production
|
|
fi
|
|
|
|
# Load site configs
|
|
IFS=$'\n'$'\r'; for line in $(captaincore site get $site --bash --captain-id=$CAPTAIN_ID); do declare "$line"; done; unset IFS
|
|
|
|
# --------------------------------------------------
|
|
# Skip if recently updated
|
|
# --------------------------------------------------
|
|
if [[ -n "$SKIP_IF_RECENT" ]]; then
|
|
update_list_file="$path/${site}_${site_id}/${environment}/update-logs/list.json"
|
|
should_skip=$(php ${CAPTAINCORE_PATH}/lib/local-scripts/check-last-run.php "$update_list_file" "$SKIP_IF_RECENT")
|
|
if [[ "$should_skip" == "true" ]]; then
|
|
echo "Skipping $site ($environment) - Updated within last $SKIP_IF_RECENT."
|
|
return
|
|
fi
|
|
fi
|
|
# --------------------------------------------------
|
|
|
|
rclone_config_file="$path/${site}_${site_id}/rclone.conf"
|
|
ftp_output=$( { rclone lsd ${environment}:$home_directory --config="$rclone_config_file" ; } 2>&1 )
|
|
ftp_search_for_wordpress=$( echo "$ftp_output" | perl -wnE'say for /wp-admin/g' )
|
|
|
|
if [[ $ftp_search_for_wordpress != "wp-admin"* ]]; then
|
|
echo "Error: WordPress not found $site-$environment"
|
|
return
|
|
fi
|
|
|
|
cd ${CAPTAINCORE_PATH}/data
|
|
|
|
echo "Quicksave before update..."
|
|
captaincore quicksave generate $site-$environment --captain-id=$CAPTAIN_ID > /dev/null 2>&1
|
|
quicksave_id_before=$( captaincore quicksave latest $site-$environment --field=hash --captain-id=$CAPTAIN_ID )
|
|
plugin_count_before=$( captaincore ssh $site-$environment --command="wp plugin list --format=csv --fields=name --skip-plugins --skip-themes | tail -n +2 | wc -l" --captain-id=$CAPTAIN_ID )
|
|
|
|
[[ "$CAPTAINCORE_DEBUG" == "true" ]] && echo "[debug] quicksave_id_before=$quicksave_id_before plugin_count_before=$plugin_count_before"
|
|
|
|
update_args="--all --format=json --provider=${provider}"
|
|
[[ -n "$updates_exclude_themes" ]] && update_args="$update_args --exclude_themes=$updates_exclude_themes"
|
|
[[ -n "$updates_exclude_plugins" ]] && update_args="$update_args --exclude_plugins=$updates_exclude_plugins"
|
|
[[ "$CAPTAINCORE_DEBUG" == "true" ]] && update_args="$update_args --debug"
|
|
|
|
echo "Updating ${site}-${environment}..."
|
|
[[ "$CAPTAINCORE_DEBUG" == "true" ]] && echo "[debug] Running remote update script with args: $update_args"
|
|
|
|
update_stderr_file=$(mktemp)
|
|
if [[ "$CAPTAINCORE_DEBUG" == "true" ]]; then
|
|
update_output=$( captaincore ssh ${site}-${environment} --script=update --captain-id=$CAPTAIN_ID -- $update_args 2> >(tee "$update_stderr_file" >&2) )
|
|
else
|
|
update_output=$( captaincore ssh ${site}-${environment} --script=update --captain-id=$CAPTAIN_ID -- $update_args 2>"$update_stderr_file" )
|
|
fi
|
|
update_exit=$?
|
|
|
|
update_errors=$(<"$update_stderr_file")
|
|
rm -f "$update_stderr_file"
|
|
|
|
# Surface errors when the remote script produced no output
|
|
if [[ -z "$update_output" && -n "$update_errors" ]]; then
|
|
# Filter to lines that look like real errors (not SSH banners or warnings)
|
|
real_errors=$( echo "$update_errors" | grep -iE "^(Error|Fatal|Warning):" | head -3 )
|
|
if [[ -n "$real_errors" ]]; then
|
|
echo " Error running updates:"
|
|
echo "$real_errors" | sed 's/^/ /'
|
|
return
|
|
fi
|
|
fi
|
|
|
|
# Parse and display update results
|
|
if command -v python3 &>/dev/null; then
|
|
formatted=$( echo "$update_output" | python3 -c "
|
|
import sys, json
|
|
for line in sys.stdin:
|
|
line = line.strip()
|
|
if not line:
|
|
continue
|
|
try:
|
|
items = json.loads(line)
|
|
if isinstance(items, list):
|
|
for item in items:
|
|
name = item.get('name', '')
|
|
old_v = item.get('old_version', '')
|
|
new_v = item.get('new_version', '')
|
|
status = item.get('status', '')
|
|
if status == 'Updated':
|
|
print(f' Updated {name} {old_v} \u2192 {new_v}')
|
|
elif status and name:
|
|
print(f' {name}: {status}')
|
|
except:
|
|
pass
|
|
" 2>/dev/null )
|
|
if [[ -n "$formatted" ]]; then
|
|
echo "$formatted"
|
|
else
|
|
echo " Everything up to date"
|
|
fi
|
|
else
|
|
echo "$update_output"
|
|
fi
|
|
|
|
echo "Quicksave after update..."
|
|
captaincore quicksave generate $site-$environment --captain-id=$CAPTAIN_ID > /dev/null 2>&1
|
|
quicksave_id_after=$( captaincore quicksave latest $site-$environment --field=hash --captain-id=$CAPTAIN_ID )
|
|
plugin_count_after=$( captaincore ssh $site-$environment --command="wp plugin list --format=csv --fields=name --skip-plugins --skip-themes | tail -n +2 | wc -l" --captain-id=$CAPTAIN_ID )
|
|
|
|
[[ "$CAPTAINCORE_DEBUG" == "true" ]] && echo "[debug] quicksave_id_after=$quicksave_id_after plugin_count_after=$plugin_count_after"
|
|
|
|
if [[ $plugin_count_before != $plugin_count_after ]]; then
|
|
mismatch_subject="Plugin update mismatch ($plugin_count_before:$plugin_count_after) on $home_url"
|
|
mismatch_body="Updating plugins on $home_url ($site-$environment) resulted in a mismatch count.<br /><br />Before updating there were $plugin_count_before plugins.<br />After updating there were $plugin_count_after plugins."
|
|
mismatch_content_json=$( echo "$mismatch_body" | php -r 'echo json_encode(file_get_contents("php://stdin"));' )
|
|
|
|
if [[ $captaincore_dev == true ]]; then
|
|
curl_argument="-k"
|
|
fi
|
|
|
|
curl ${curl_argument} --silent --request POST "$captaincore_api" --header "Content-Type: application/json" --data @- << EOF
|
|
{
|
|
"command": "monitor-notify",
|
|
"token": "$token",
|
|
"data": {
|
|
"email": "$captaincore_admin_email",
|
|
"subject": "$mismatch_subject",
|
|
"content": $mismatch_content_json
|
|
}
|
|
}
|
|
EOF
|
|
fi
|
|
|
|
if [[ $quicksave_id_before != $quicksave_id_after ]]; then
|
|
captaincore update-log generate $site-$environment $quicksave_id_before $quicksave_id_after --captain-id=$CAPTAIN_ID > /dev/null
|
|
captaincore update-log list-generate $site-$environment --captain-id=$CAPTAIN_ID > /dev/null
|
|
echo "Update log saved"
|
|
else
|
|
# Touch list.json so --skip-if-recent knows this site was checked
|
|
update_list_file="$path/${site}_${site_id}/${environment}/update-logs/list.json"
|
|
mkdir -p "$(dirname "$update_list_file")"
|
|
[[ ! -f "$update_list_file" ]] && echo "[]" > "$update_list_file"
|
|
touch "$update_list_file"
|
|
fi
|
|
|
|
|
|
}
|
|
|
|
run_command
|