#!/bin/bash # Function to check and install required utilities check_and_install_deps() { local deps=("skopeo" "jq" "grep" "sort" "head") local missing_deps=() # Check availability of each utility for dep in "${deps[@]}"; do if ! command -v "$dep" &> /dev/null; then missing_deps+=("$dep") fi done # If all utilities are installed, exit if [ ${#missing_deps[@]} -eq 0 ]; then echo "✓ All required utilities are installed." return 0 fi echo "❌ The following utilities are missing: ${missing_deps[*]}" echo "🔍 Attempting to install..." # Determine package manager and install missing utilities if command -v apt &> /dev/null; then # Debian/Ubuntu sudo apt update sudo apt install -y "${missing_deps[@]}" elif command -v apt-get &> /dev/null; then # Debian/Ubuntu (alternative) sudo apt-get update sudo apt-get install -y "${missing_deps[@]}" elif command -v pacman &> /dev/null; then # Arch Linux for dep in "${missing_deps[@]}"; do case $dep in "skopeo") sudo pacman -S --noconfirm skopeo ;; "jq") sudo pacman -S --noconfirm jq ;; "grep"|"sort"|"head") # These utilities are usually part of coreutils sudo pacman -S --noconfirm coreutils ;; esac done elif command -v apk &> /dev/null; then # Alpine Linux sudo apk add "${missing_deps[@]}" elif command -v yum &> /dev/null; then # RHEL/CentOS 7 sudo yum install -y epel-release sudo yum install -y "${missing_deps[@]}" elif command -v dnf &> /dev/null; then # Fedora/RHEL 8+ sudo dnf install -y "${missing_deps[@]}" elif command -v zypper &> /dev/null; then # openSUSE sudo zypper install -y "${missing_deps[@]}" else echo "❌ Could not determine package manager. Install utilities manually: ${missing_deps[*]}" exit 1 fi # Check if utilities were installed successfully local failed_deps=() for dep in "${missing_deps[@]}"; do if ! command -v "$dep" &> /dev/null; then failed_deps+=("$dep") fi done if [ ${#failed_deps[@]} -gt 0 ]; then echo "❌ Failed to install: ${failed_deps[*]}" exit 1 else echo "✓ All missing utilities were successfully installed." fi } # Function to display help show_help() { echo "Usage: $0 [number_of_tags]" echo "" echo "Arguments:" echo " - Docker repository URL or name (required)" echo " [number_of_tags] - number of recent tags to keep (default: 3)" echo "" echo "Examples:" echo " $0 docker.io/library/alpine" echo " $0 myregistry.local:5000/myapp 5" echo " $0 registry.example.com/project/image 10" } # Check for the first argument if [ -z "$1" ]; then echo "❌ Error: repository not specified" echo "" show_help exit 1 fi # Check and install dependencies check_and_install_deps # Set the number of tags to keep KEEP_TAGS=${2:-3} # Check that the number of tags is a positive number if ! [[ "$KEEP_TAGS" =~ ^[0-9]+$ ]] || [ "$KEEP_TAGS" -lt 1 ]; then echo "❌ Error: number of tags must be a positive number" exit 1 fi echo "🔍 Fetching list of tags for $1..." echo "📦 Will keep $KEEP_TAGS recent tags (excluding latest)" # Fetch all tags (sorted alphabetically, which is chronological for YYYYMMDDHHMMSS-hash format) allTags=$(skopeo list-tags docker://"$1" 2>/dev/null | jq -r '.Tags[]' | sort) if [ -z "$allTags" ]; then echo "❌ Error: could not fetch tag list or repository is empty" exit 1 fi # Count total number of tags2 totalTags=$(echo "$allTags" | wc -l) # Determine how many tags to delete tagsToDelete=$((totalTags - KEEP_TAGS - 1)) # -1 for latest if [ "$tagsToDelete" -le 0 ]; then echo "✓ Total tags: $totalTags (including latest)" echo "✓ Nothing to delete, keeping all $totalTags tags" exit 0 fi # Get tags to delete (exclude latest and keep KEEP_TAGS recent ones) oldTags=$(echo "$allTags" | grep -v "latest" | head -n -"$KEEP_TAGS") echo "📊 Total tags: $totalTags (including latest)" echo "🗑️ Will be deleted: $(echo "$oldTags" | wc -l) tags" echo "" # Delete old tags for tag in $oldTags; do echo " ➜ Deleting: $tag" if skopeo delete docker://"$1:$tag" 2>/dev/null; then echo " ✓ Successfully deleted" else echo " ❌ Error deleting $tag" fi done echo "" echo "✅ Done!" echo "📝 Kept: $KEEP_TAGS recent tags and latest"