#!/usr/bin/env bash set -o pipefail # Colors and styles readonly RESET='\033[0m' readonly BOLD='\033[1m' readonly DIM='\033[2m' readonly UNDERLINE='\033[4m' readonly BLUE='\033[34m' readonly GREEN='\033[32m' readonly RED='\033[31m' readonly YELLOW='\033[33m' readonly CYAN='\033[36m' readonly MAGENTA='\033[35m' # Essential emojis readonly ROCKET="🚀" readonly CHECK="✓" readonly ERROR="❌" readonly SKIP="⏭️" # Configuration readonly RELEASE_BRANCH="2.x" readonly REPOSITORIES=( "flasher" "flasher-laravel" "flasher-symfony" "flasher-noty" "flasher-noty-laravel" "flasher-noty-symfony" "flasher-notyf" "flasher-notyf-laravel" "flasher-notyf-symfony" "flasher-sweetalert" "flasher-sweetalert-laravel" "flasher-sweetalert-symfony" "flasher-toastr" "flasher-toastr-laravel" "flasher-toastr-symfony" ) print_header() { echo -e "\n${BOLD}${BLUE}${ROCKET} PHP-Flasher Release ${ROCKET}${RESET}\n" echo -e "${BOLD}Date : ${RESET}${CYAN}$(date -u '+%Y-%m-%d %H:%M:%S') UTC${RESET}" echo -e "${BOLD}User : ${RESET}${MAGENTA}$(whoami)${RESET}" echo -e "${BOLD}Branch : ${RESET}${GREEN}$RELEASE_BRANCH${RESET}" echo -e "${BOLD}Directory : ${RESET}${BLUE}$(pwd)${RESET}\n" } draw_progress_bar() { local percent=$1 local width=50 local filled=$(((width * percent + 99) / 100)) # Rounded up division local empty=$((width - filled)) echo -n "[" printf "${GREEN}█%.0s${RESET}" $(seq 1 $filled) printf "${DIM}─%.0s${RESET}" $(seq 1 $empty) echo -n "] ${percent}%" } check_tag_exists() { local repo=$1 local tag=$2 local remote_url="git@github.com:php-flasher/$repo.git" if git ls-remote --tags "$remote_url" | grep -q "refs/tags/$tag$"; then return 0 else return 1 fi } release_repository() { local repo=$1 local version=$2 local tmp_dir="/tmp/php-flasher" local remote_url="git@github.com:php-flasher/$repo.git" echo -e "\nGitHub : ${UNDERLINE}${BLUE}https://github.com/php-flasher/${repo}${RESET}" echo -e "Tag : ${YELLOW}$version${RESET}" if check_tag_exists "$repo" "$version"; then echo -e "${SKIP} ${YELLOW}Tag $version already exists, skipping...${RESET}" return 0 fi # Clean and create temporary directory rm -rf "$tmp_dir" mkdir -p "$tmp_dir" echo -e "${CYAN}Cloning repository...${RESET}" if ! git clone "$remote_url" "$tmp_dir" >/dev/null 2>&1; then echo -e "${ERROR} ${RED}Failed to clone repository${RESET}" return 1 fi ( cd "$tmp_dir" echo -e "${CYAN}Creating tag $version...${RESET}" git checkout "$RELEASE_BRANCH" >/dev/null 2>&1 git tag "$version" if ! git push origin --tags --force >/dev/null 2>&1; then echo -e "${ERROR} ${RED}Failed to push tag${RESET}" return 1 fi ) echo -e "${CHECK} ${GREEN}Successfully tagged${RESET}" return 0 } validate_version() { local version=$1 if [[ ! $version =~ ^v?[0-9]+\.[0-9]+\.[0-9]+$ ]]; then echo -e "\n${ERROR} ${RED}Invalid version format: $version${RESET}" echo -e "Version must be in format X.Y.Z or vX.Y.Z (e.g., 2.1.6 or v2.1.6)\n" exit 1 fi } validate_environment() { echo -e "${CYAN}Validating environment...${RESET}" local has_error=0 # Check branch local current_branch=$(git rev-parse --abbrev-ref HEAD) echo -ne "${CYAN}Checking branch...${RESET} " if [[ "$RELEASE_BRANCH" != "$current_branch" ]]; then echo -e "${ERROR} ${RED}Wrong branch: $current_branch (expected: $RELEASE_BRANCH)${RESET}" has_error=1 else echo -e "${CHECK} ${GREEN}On correct branch: $current_branch${RESET}" fi # Check working directory echo -ne "${CYAN}Checking working directory...${RESET} " if [[ ! -z "$(git status --porcelain)" ]]; then echo -e "${ERROR} ${RED}Working directory is not clean${RESET}" echo -e "${DIM}Hint: Commit or stash your changes first${RESET}" has_error=1 else echo -e "${CHECK} ${GREEN}Working directory is clean${RESET}" fi # Check sync with remote echo -ne "${CYAN}Checking remote synchronization...${RESET} " git fetch origin > /dev/null 2>&1 local local_sha=$(git rev-parse HEAD) local remote_sha=$(git rev-parse origin/$RELEASE_BRANCH) if [[ $local_sha != $remote_sha ]]; then echo -e "${ERROR} ${RED}Branch is not in sync with origin/$RELEASE_BRANCH${RESET}" echo -e "\n${YELLOW}Local SHA: ${local_sha}${RESET}" echo -e "${YELLOW}Remote SHA: ${remote_sha}${RESET}" echo -e "\n${DIM}To fix this, try:${RESET}" # Check if we have unpushed commits if git rev-list origin/$RELEASE_BRANCH..$RELEASE_BRANCH --count > /dev/null 2>&1; then local ahead=$(git rev-list origin/$RELEASE_BRANCH..$RELEASE_BRANCH --count) local behind=$(git rev-list $RELEASE_BRANCH..origin/$RELEASE_BRANCH --count) if [[ $ahead -gt 0 && $behind -gt 0 ]]; then echo -e "${YELLOW}Your branch is $ahead commits ahead and $behind commits behind origin/$RELEASE_BRANCH${RESET}" echo -e "1. ${CYAN}git pull origin $RELEASE_BRANCH${RESET} (to get remote changes)" echo -e "2. ${CYAN}git push origin $RELEASE_BRANCH${RESET} (to push your changes)" elif [[ $ahead -gt 0 ]]; then echo -e "${YELLOW}Your branch is $ahead commits ahead of origin/$RELEASE_BRANCH${RESET}" echo -e "Run: ${CYAN}git push origin $RELEASE_BRANCH${RESET}" elif [[ $behind -gt 0 ]]; then echo -e "${YELLOW}Your branch is $behind commits behind origin/$RELEASE_BRANCH${RESET}" echo -e "Run: ${CYAN}git pull origin $RELEASE_BRANCH${RESET}" fi fi has_error=1 else echo -e "${CHECK} ${GREEN}Branch is in sync with remote${RESET}" fi if [[ $has_error -eq 1 ]]; then echo -e "\n${ERROR} ${RED}Environment validation failed${RESET}" exit 1 fi echo -e "\n${CHECK} ${GREEN}Environment validated successfully${RESET}\n" } main() { if [ "$#" -ne 1 ]; then echo -e "${ERROR} ${RED}Version tag required${RESET}" echo -e "Usage: $0 " echo -e "Example: $0 2.1.6\n" exit 1 fi local version=$1 [[ $version != v* ]] && version="v$version" print_header validate_version "$version" validate_environment local success_count=0 local skipped_count=0 local failed_count=0 local total_count=${#REPOSITORIES[@]} local start_time=$(date +%s) for repo in "${REPOSITORIES[@]}"; do local current_count=$((success_count + skipped_count + failed_count + 1)) local percent=$((current_count * 100 / total_count)) echo -e "\nProgress: ${BOLD}$current_count/$total_count${RESET}" # draw_progress_bar $percent if release_repository "$repo" "$version"; then if check_tag_exists "$repo" "$version"; then ((skipped_count++)) else ((success_count++)) fi else ((failed_count++)) fi done local end_time=$(date +%s) local duration=$((end_time - start_time)) # Summary echo -e "\n${BOLD}${CYAN}Release Summary${RESET}" echo -e "Successful : ${GREEN}$success_count${RESET}" echo -e "Skipped : ${YELLOW}$skipped_count${RESET}" [ $failed_count -gt 0 ] && echo -e "Failed : ${RED}$failed_count${RESET}" echo -e "Duration : ${YELLOW}${duration}s${RESET}" echo -e "Total repos: ${CYAN}$total_count${RESET}\n" [ $failed_count -gt 0 ] && exit 1 || exit 0 } main "$@"