Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 96 additions & 4 deletions mage
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ MAGE_VERSION="2.5.2"
# Check if this is the Magento 2 root
if [[ ! -d app/etc ]]; then
case "$1" in
version|help|self-update|install|setup|create)
version|help|self-update|install|setup|create|destroy)
# Allow these commands to run even if not in Magento root
;;
*)
Expand Down Expand Up @@ -89,6 +89,89 @@ if [ -f .env ] && grep -q "WARDEN_ENV_NAME" .env && [[ ! "$PATH" == /var/www/htm
PURGE_CLI="warden env exec -T php-fpm rm -rf"
fi

# Fully remove a Magento project: folder, database, and all Valet links/certs.
# Run from the PARENT directory of the project, e.g.:
# cd ~/Developer/magento && mage destroy my-project
function mage_destroy_project() {
local name="$1"

if [[ -z "$name" ]]; then
echo "Usage: mage destroy <PROJECT-NAME>"
return 1
fi

if [[ ! -d "$name" ]]; then
echo "Error: Directory '${name}' not found in the current folder ($(pwd))."
echo "Run this command from the parent directory of the project."
return 1
fi

# Gather Valet domains by reading .valet-env.php — only top-level array keys
# (the ones with array values) are domain names; string-value keys are skipped.
local valet_env="${name}/.valet-env.php"
local domains=()
if [[ -f "$valet_env" ]]; then
while IFS= read -r _d; do
[[ -n "$_d" ]] && domains+=("$_d")
done < <(python3 -c "
import re, sys
content = open(sys.argv[1]).read()
for k in re.findall(r\"'([^']+)'\\s*=>\\s*\\[\", content):
print(k)
" "$valet_env")
fi

echo ""
echo -e "${RED}WARNING: This will permanently destroy:${RESET}"
echo " • Project folder : $(pwd)/${name}"
echo " • Database : ${name}"
if [[ ${#domains[@]} -gt 0 ]]; then
echo " • Valet domains : ${domains[*]}"
fi
echo ""
read -p "Type the project name to confirm: " _confirm && echo ""

if [[ "$_confirm" != "$name" ]]; then
echo -e "Aborted — '${_confirm}' does not match '${name}'."
return 1
fi

# Valet cleanup — delete cert files, nginx configs, and site symlinks directly
# so we can do a single valet restart instead of one nginx restart per domain.
if [[ $VALET == 1 && ${#domains[@]} -gt 0 ]]; then
local _valet_cfg="$HOME/.config/valet"
echo "Removing Valet certificates, nginx configs and site links..."
for d in "${domains[@]}"; do
rm -f "${_valet_cfg}/Certificates/${d}.test.crt" \
"${_valet_cfg}/Certificates/${d}.test.csr" \
"${_valet_cfg}/Certificates/${d}.test.key" \
"${_valet_cfg}/Certificates/${d}.test.conf"
rm -f "${_valet_cfg}/Nginx/${d}.test"
rm -f "${_valet_cfg}/Sites/${d}"
sudo security delete-certificate -c "${d}.test" \
/Library/Keychains/System.keychain 2>/dev/null || true
done
echo "Restarting nginx once..."
valet restart
fi

# Drop database
echo "Dropping database '${name}'..."
if command -v mysql &>/dev/null; then
mysql -uroot -proot -e "DROP DATABASE IF EXISTS \`${name}\`;" 2>/dev/null \
|| echo " Warning: could not drop database (check credentials)."
else
echo " Warning: mysql not found — skipping database removal."
fi

# Remove project folder
echo "Removing project folder '${name}'..."
rm -rf "${name}"

echo ""
echo -e "${GREEN}✓ Project '${name}' has been fully removed.${RESET}"
}

# Creates a file/folder and echo the contents in one command
function mage_make_file() {
touch $1
Expand Down Expand Up @@ -347,6 +430,7 @@ function mage_help() {
mage_help_cmd "create [NAME]" "Alias for 'mage install' and 'mage setup'"
mage_help_cmd "install [NAME]" "Installs a new Magento 2 Project"
mage_help_cmd "setup [NAME]" "Configures and sets up the new Magento 2 Project"
mage_help_cmd "destroy [NAME]" "Fully remove a project (folder, DB, Valet links & certs)"

mage_help_sub_header "Development"
mage_help_cmd "start" "Open store and admin with code editor and git client"
Expand Down Expand Up @@ -871,9 +955,6 @@ function mage_add_sample() {
touch README.md
php -f $HOME/.magento-sampledata/$mversion/dev/tools/build-sample-data.php -- --ce-source="$PWD"

# Unset default styles from sample data
$MAGENTO_CLI config:set design/head/includes "" &> /dev/null

$MAGENTO_CLI setup:upgrade

# Set theme to Hyva if present
Expand All @@ -883,6 +964,9 @@ function mage_add_sample() {
fi
fi

# Unset default styles from sample data
$MAGENTO_CLI config:set design/head/includes "" &> /dev/null

$MAGENTO_CLI indexer:reindex
$MAGENTO_CLI cache:flush
}
Expand Down Expand Up @@ -1055,6 +1139,14 @@ case "${@}" in
echo "No name was given for the magento project, aborting.."
;;

"destroy")
echo "No project name given. Usage: mage destroy <PROJECT-NAME>"
;;

"destroy "*)
mage_destroy_project "$2"
;;

"create "*)
mage_install $2
mage_setup
Expand Down
82 changes: 82 additions & 0 deletions src/_destroy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Fully remove a Magento project: folder, database, and all Valet links/certs.
# Run from the PARENT directory of the project, e.g.:
# cd ~/Developer/magento && mage destroy my-project
function mage_destroy_project() {
local name="$1"

if [[ -z "$name" ]]; then
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rework to work directly from the project folder

echo "Usage: mage destroy <PROJECT-NAME>"
return 1
fi

if [[ ! -d "$name" ]]; then
echo "Error: Directory '${name}' not found in the current folder ($(pwd))."
echo "Run this command from the parent directory of the project."
return 1
fi

# Gather Valet domains by reading .valet-env.php — only top-level array keys
# (the ones with array values) are domain names; string-value keys are skipped.
local valet_env="${name}/.valet-env.php"
local domains=()
if [[ -f "$valet_env" ]]; then
while IFS= read -r _d; do
[[ -n "$_d" ]] && domains+=("$_d")
done < <(python3 -c "
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Convert to php

import re, sys
content = open(sys.argv[1]).read()
for k in re.findall(r\"'([^']+)'\\s*=>\\s*\\[\", content):
print(k)
" "$valet_env")
fi

echo ""
echo -e "${RED}WARNING: This will permanently destroy:${RESET}"
echo " • Project folder : $(pwd)/${name}"
echo " • Database : ${name}"
if [[ ${#domains[@]} -gt 0 ]]; then
echo " • Valet domains : ${domains[*]}"
fi
echo ""
read -p "Type the project name to confirm: " _confirm && echo ""

if [[ "$_confirm" != "$name" ]]; then
echo -e "Aborted — '${_confirm}' does not match '${name}'."
return 1
fi

# Valet cleanup — delete cert files, nginx configs, and site symlinks directly
# so we can do a single valet restart instead of one nginx restart per domain.
if [[ $VALET == 1 && ${#domains[@]} -gt 0 ]]; then
local _valet_cfg="$HOME/.config/valet"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optimize

echo "Removing Valet certificates, nginx configs and site links..."
for d in "${domains[@]}"; do
rm -f "${_valet_cfg}/Certificates/${d}.test.crt" \
"${_valet_cfg}/Certificates/${d}.test.csr" \
"${_valet_cfg}/Certificates/${d}.test.key" \
"${_valet_cfg}/Certificates/${d}.test.conf"
rm -f "${_valet_cfg}/Nginx/${d}.test"
rm -f "${_valet_cfg}/Sites/${d}"
sudo security delete-certificate -c "${d}.test" \
/Library/Keychains/System.keychain 2>/dev/null || true
done
echo "Restarting nginx once..."
valet restart
fi

# Drop database
echo "Dropping database '${name}'..."
if command -v mysql &>/dev/null; then
mysql -uroot -proot -e "DROP DATABASE IF EXISTS \`${name}\`;" 2>/dev/null \
|| echo " Warning: could not drop database (check credentials)."
else
echo " Warning: mysql not found — skipping database removal."
fi

# Remove project folder
echo "Removing project folder '${name}'..."
rm -rf "${name}"

echo ""
echo -e "${GREEN}✓ Project '${name}' has been fully removed.${RESET}"
}
2 changes: 1 addition & 1 deletion src/_global.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ MAGE_VERSION="2.5.2"
# Check if this is the Magento 2 root
if [[ ! -d app/etc ]]; then
case "$1" in
version|help|self-update|install|setup|create)
version|help|self-update|install|setup|create|destroy)
# Allow these commands to run even if not in Magento root
;;
*)
Expand Down
1 change: 1 addition & 0 deletions src/_info.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ function mage_help() {
mage_help_cmd "create [NAME]" "Alias for 'mage install' and 'mage setup'"
mage_help_cmd "install [NAME]" "Installs a new Magento 2 Project"
mage_help_cmd "setup [NAME]" "Configures and sets up the new Magento 2 Project"
mage_help_cmd "destroy [NAME]" "Fully remove a project (folder, DB, Valet links & certs)"

mage_help_sub_header "Development"
mage_help_cmd "start" "Open store and admin with code editor and git client"
Expand Down
8 changes: 8 additions & 0 deletions src/_mage.sh
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ case "${@}" in
echo "No name was given for the magento project, aborting.."
;;

"destroy")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add alias nuke

echo "No project name given. Usage: mage destroy <PROJECT-NAME>"
;;

"destroy "*)
mage_destroy_project "$2"
;;

"create "*)
mage_install $2
mage_setup
Expand Down