From 1139a9813b5006b0a5581927dc8ee91d020aa84f Mon Sep 17 00:00:00 2001 From: Matty Evans Date: Fri, 17 Jan 2025 15:58:34 +1000 Subject: [PATCH 1/4] feat: Add uninstall functionality --- install.sh | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 88 insertions(+), 2 deletions(-) diff --git a/install.sh b/install.sh index 22a9dcf..a692f42 100755 --- a/install.sh +++ b/install.sh @@ -89,9 +89,10 @@ warn() { } usage() { - echo "Usage: $0 [-p path] [-v version]" + echo "Usage: $0 [-p path] [-v version] [-u]" echo " -p: Path to install contributoor (default: $HOME/.contributoor)" echo " -v: Version of contributoor to install without 'v' prefix (default: latest, example: 0.0.6)" + echo " -u: Uninstall Contributoor" exit 1 } @@ -592,12 +593,97 @@ EOF } } +uninstall() { + printf "\n${COLOR_RED}Warning, this will:${COLOR_RESET}\n" + printf " • Stop and remove any contributoor services (systemd/launchd)\n" + printf " • Stop and remove any contributoor Docker containers and images\n" + printf " • Remove contributoor from your PATH\n" + printf " • Delete all contributoor data from ${HOME}/.contributoor\n\n" + printf "Are you sure you want to uninstall? [y/N]: " + read -r confirm + case "$(echo "$confirm" | tr '[:upper:]' '[:lower:]')" in + y|yes) ;; + *) printf "\nUninstall cancelled\n"; exit 1 ;; + esac + + printf "\n${COLOR_RED}Uninstalling contributoor...${COLOR_RESET}\n" + + # First stop all services based on platform + case "$(detect_platform)" in + "darwin") + if sudo launchctl list | grep -q "io.ethpandaops.contributoor"; then + sudo launchctl stop io.ethpandaops.contributoor + sudo launchctl unload -w "/Library/LaunchDaemons/io.ethpandaops.contributoor.plist" + success "Stopped launchd service" + + sudo rm -f "/Library/LaunchDaemons/io.ethpandaops.contributoor.plist" + success "Removed launchd service files" + fi + ;; + *) + if command -v systemctl >/dev/null 2>&1 && sudo systemctl list-unit-files | grep -q "contributoor.service"; then + sudo systemctl stop contributoor.service + success "Stopped systemd service" + + sudo systemctl disable contributoor.service >/dev/null 2>&1 + sudo rm -f "/etc/systemd/system/contributoor.service" + sudo rm -rf "/etc/systemd/system/contributoor.service.d" + sudo rm -f "/etc/systemd/system/contributoor.service.wants" + sudo rm -f "/etc/systemd/system/multi-user.target.wants/contributoor.service" + sudo systemctl daemon-reload + success "Removed systemd service files" + fi + ;; + esac + + # Stop and clean up docker containers and images if they exist + if command -v docker >/dev/null 2>&1; then + # Stop running containers first + if docker ps | grep -q "contributoor"; then + docker stop $(docker ps | grep "contributoor" | awk '{print $1}') >/dev/null 2>&1 + success "Stopped Docker containers" + fi + + # Remove containers + if docker ps -a | grep -q "contributoor"; then + docker rm -f $(docker ps -a | grep "contributoor" | awk '{print $1}') >/dev/null 2>&1 + success "Removed Docker containers" + fi + + # Remove images + if docker images | grep -q "ethpandaops/contributoor"; then + docker rmi -f $(docker images | grep "ethpandaops/contributoor" | awk '{print $3}') >/dev/null 2>&1 + success "Removed Docker images" + fi + fi + + # Remove PATH entry from shell config + for rc in "$HOME/.bashrc" "$HOME/.zshrc" "$HOME/.bash_profile" "$HOME/.profile"; do + if [ -f "$rc" ]; then + temp_file=$(mktemp) + grep -v "export PATH=.*contributoor.*bin" "$rc" > "$temp_file" + mv "$temp_file" "$rc" + success "Cleaned PATH from $rc" + fi + done + + # Remove contributoor directory + if [ -d "$HOME/.contributoor" ]; then + rm -rf "$HOME/.contributoor" + success "Removed contributoor directory" + fi + + printf "\n\n${COLOR_GREEN}Contributoor has been uninstalled successfully${COLOR_RESET}\n\n" + exit 0 +} + main() { # Parse arguments - while getopts "p:v:h" FLAG; do + while getopts "p:v:hu" FLAG; do case "$FLAG" in p) CONTRIBUTOOR_PATH="$OPTARG" ;; v) CONTRIBUTOOR_VERSION="$OPTARG" ;; + u) uninstall ;; h) usage ;; *) usage ;; esac From 3d82bd7ab2dba87892a20035a9aee5eb52b04aff Mon Sep 17 00:00:00 2001 From: Matty Evans Date: Fri, 17 Jan 2025 16:01:39 +1000 Subject: [PATCH 2/4] docs: Add uninstall instructions to README --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index b71d19a..fb521f4 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,15 @@ This repository contains the installer for the [contributoor](https://github.com ``` +
+ 😔 Uninstall + + Uninstalling contributoor can be done by running the installer with the `-u` flag: + ```bash + curl -O https://raw.githubusercontent.com/ethpandaops/contributoor-installer/refs/heads/master/install.sh && chmod +x install.sh && ./install.sh -u + ``` +
+ ## ⚙️ Post-Installation > **Note:** you may need to start a new shell session before you can run the `contributoor` command. From a3a72f5fae1bab102f1154bdfbeb84dff5b1734c Mon Sep 17 00:00:00 2001 From: Matty Evans Date: Fri, 17 Jan 2025 16:20:47 +1000 Subject: [PATCH 3/4] test: add uninstall test cases --- install.bats | 197 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 196 insertions(+), 1 deletion(-) diff --git a/install.bats b/install.bats index f6b85de..f2eb729 100644 --- a/install.bats +++ b/install.bats @@ -862,10 +862,18 @@ EOF "launchctl") case "$2" in "list") echo "12345 0 io.ethpandaops.contributoor" ;; + "stop") printf "\n${COLOR_GREEN}✓ Stopped launchd service${COLOR_RESET}" ;; + "unload") printf "\n${COLOR_GREEN}✓ Removed launchd service files${COLOR_RESET}" ;; *) return 0 ;; esac ;; - *) return 0 ;; + "rm") + "${@:1}" + ;; + *) + "${@:2}" + return 0 + ;; esac } export -f sudo @@ -994,4 +1002,191 @@ EOF [ "$result" -eq 0 ] echo "$output" | grep -q "You can start contributoor later" +} + +@test "uninstall handles user confirmation correctly" { + # Create test environment + mkdir -p "$TEST_DIR/.contributoor" + touch "$TEST_DIR/.zshrc" + echo 'export PATH="$PATH:/some/path/.contributoor/bin"' >> "$TEST_DIR/.zshrc" + + # Setup mock functions + function detect_platform() { echo "darwin"; } + function sudo() { "${@:2}"; return 0; } + function docker() { + case "$1" in + "ps") echo "123 contributoor" ;; + "images") echo "456 ethpandaops/contributoor" ;; + "stop") return 0 ;; + "rm") return 0 ;; + "rmi") return 0 ;; + *) return 0 ;; + esac + } + export -f detect_platform sudo docker + export HOME="$TEST_DIR" + + # Test 'no' response + run bash -c ' + source ./install.sh + printf "n\n" | uninstall + ' + [ "$status" -eq 1 ] + echo "$output" | grep -q "Uninstall cancelled" + + # Test 'yes' response + run bash -c ' + source ./install.sh + printf "y\n" | uninstall + ' + [ "$status" -eq 0 ] + echo "$output" | grep -q "Uninstalling contributoor" + echo "$output" | grep -q "Contributoor has been uninstalled successfully" +} + +@test "uninstall cleans up all components" { + # Create test environment + mkdir -p "$TEST_DIR/.contributoor/bin" + touch "$TEST_DIR/.zshrc" + echo 'export PATH="$PATH:/some/path/.contributoor/bin"' >> "$TEST_DIR/.zshrc" + export HOME="$TEST_DIR" + + # Run uninstall with 'yes' response + run bash -c ' + source ./install.sh + + # Setup mock functions + detect_platform() { echo "linux"; } + command() { + case "$2" in + "systemctl") return 0 ;; + "docker") return 0 ;; + *) command "$@" ;; + esac + } + sudo() { + case "$1" in + "systemctl") + case "$2" in + "list-unit-files") echo "contributoor.service enabled" ;; + "stop") printf "\n${COLOR_GREEN}✓ Stopped systemd service${COLOR_RESET}" ;; + "disable") printf "\n${COLOR_GREEN}✓ Disabled systemd service${COLOR_RESET}" ;; + *) return 0 ;; + esac + ;; + "rm") + "${@:1}" + ;; + *) + "${@:2}" + return 0 + ;; + esac + } + docker() { + case "$1" in + "ps") + [ "$2" = "-a" ] && echo "123 contributoor" || echo "123 contributoor" + ;; + "images") echo "456 ethpandaops/contributoor" ;; + "stop") printf "\n${COLOR_GREEN}✓ Stopped Docker containers${COLOR_RESET}" ;; + "rm") printf "\n${COLOR_GREEN}✓ Removed Docker containers${COLOR_RESET}" ;; + "rmi") printf "\n${COLOR_GREEN}✓ Removed Docker images${COLOR_RESET}" ;; + *) return 0 ;; + esac + } + export -f detect_platform command sudo docker + + printf "y\n" | uninstall + ' + + # Check status and output + [ "$status" -eq 0 ] + + # Verify systemd cleanup + echo "$output" | grep -q "Stopped systemd service" + echo "$output" | grep -q "Removed systemd service files" + + # Verify docker cleanup + echo "$output" | grep -q "Stopped Docker containers" + echo "$output" | grep -q "Removed Docker containers" + echo "$output" | grep -q "Removed Docker images" + + # Verify PATH cleanup + echo "$output" | grep -q "Cleaned PATH from" + ! grep -q "contributoor" "$TEST_DIR/.zshrc" + + # Verify directory cleanup + [ ! -d "$TEST_DIR/.contributoor" ] +} + +@test "uninstall handles darwin platform correctly" { + # Create test environment + mkdir -p "$TEST_DIR/.contributoor" + + # Setup mock functions + function detect_platform() { echo "darwin"; } + function sudo() { + case "$1" in + "launchctl") + case "$2" in + "list") echo "123 0 io.ethpandaops.contributoor" ;; + "stop") printf "\n${COLOR_GREEN}✓ Stopped launchd service${COLOR_RESET}" ;; + "unload") printf "\n${COLOR_GREEN}✓ Removed launchd service files${COLOR_RESET}" ;; + *) return 0 ;; + esac + ;; + "rm") + "${@:1}" + ;; + *) + "${@:2}" + return 0 + ;; + esac + } + export -f detect_platform sudo + export HOME="$TEST_DIR" + + # Run uninstall with 'yes' response + run bash -c ' + source ./install.sh + printf "y\n" | uninstall + ' + + # Check status and output + [ "$status" -eq 0 ] + echo "$output" | grep -q "Stopped launchd service" + echo "$output" | grep -q "Removed launchd service files" +} + +@test "uninstall handles missing components gracefully" { + # Create minimal test environment. + mkdir -p "$TEST_DIR" + + # Setup mock functions. + function detect_platform() { echo "linux"; } + function command() { + case "$2" in + "systemctl") return 1 ;; # systemd not available + "docker") return 1 ;; # docker not available + *) command "$@" ;; + esac + } + function sudo() { + "${@:2}" + return 0 + } + export -f detect_platform command sudo + export HOME="$TEST_DIR" + + # Run uninstall with 'yes' response. + run bash -c ' + source ./install.sh + printf "y\n" | uninstall + ' + + # Should complete successfully even with nothing to clean. + [ "$status" -eq 0 ] + echo "$output" | grep -q "Contributoor has been uninstalled successfully" } \ No newline at end of file From b2c5c1dcc015477b99bff5d78154b8ee85b4412c Mon Sep 17 00:00:00 2001 From: Matty Evans Date: Fri, 17 Jan 2025 16:25:24 +1000 Subject: [PATCH 4/4] refactor: Refactor mock function setup in uninstall test --- install.bats | 47 ++++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/install.bats b/install.bats index f2eb729..a68c55f 100644 --- a/install.bats +++ b/install.bats @@ -1123,34 +1123,35 @@ EOF @test "uninstall handles darwin platform correctly" { # Create test environment mkdir -p "$TEST_DIR/.contributoor" - - # Setup mock functions - function detect_platform() { echo "darwin"; } - function sudo() { - case "$1" in - "launchctl") - case "$2" in - "list") echo "123 0 io.ethpandaops.contributoor" ;; - "stop") printf "\n${COLOR_GREEN}✓ Stopped launchd service${COLOR_RESET}" ;; - "unload") printf "\n${COLOR_GREEN}✓ Removed launchd service files${COLOR_RESET}" ;; - *) return 0 ;; - esac - ;; - "rm") - "${@:1}" - ;; - *) - "${@:2}" - return 0 - ;; - esac - } - export -f detect_platform sudo export HOME="$TEST_DIR" # Run uninstall with 'yes' response run bash -c ' source ./install.sh + + # Setup mock functions + detect_platform() { echo "darwin"; } + sudo() { + case "$1" in + "launchctl") + case "$2" in + "list") echo "123 0 io.ethpandaops.contributoor" ;; + "stop") printf "\n${COLOR_GREEN}✓ Stopped launchd service${COLOR_RESET}" ;; + "unload") printf "\n${COLOR_GREEN}✓ Removed launchd service files${COLOR_RESET}" ;; + *) return 0 ;; + esac + ;; + "rm") + "${@:1}" + ;; + *) + "${@:2}" + return 0 + ;; + esac + } + export -f detect_platform sudo + printf "y\n" | uninstall '