|
| 1 | +#!/usr/bin/env bash |
| 2 | +# Install Node (via nvm + Node.js 24 when Node is missing), enable Corepack, |
| 3 | +# install GitHub CLI when missing, and install @patternfly/patternfly-cli globally. |
| 4 | + |
| 5 | +set -euo pipefail |
| 6 | + |
| 7 | +NVM_VERSION="${NVM_VERSION:-v0.40.3}" |
| 8 | + |
| 9 | +error() { |
| 10 | + printf '\n[%s] ERROR: %s\n\n' "$(date -u +'%Y-%m-%dT%H:%M:%SZ')" "$*" >&2 |
| 11 | + exit 1 |
| 12 | +} |
| 13 | + |
| 14 | +info() { |
| 15 | + printf '[install] %s\n' "$*" |
| 16 | +} |
| 17 | + |
| 18 | +warn() { |
| 19 | + printf '[install] WARNING: %s\n' "$*" >&2 |
| 20 | +} |
| 21 | + |
| 22 | +require_cmd() { |
| 23 | + command -v "$1" >/dev/null 2>&1 |
| 24 | +} |
| 25 | + |
| 26 | +ensure_nvm_loaded() { |
| 27 | + export NVM_DIR="${NVM_DIR:-$HOME/.nvm}" |
| 28 | + if [ -s "$NVM_DIR/nvm.sh" ]; then |
| 29 | + # shellcheck source=/dev/null |
| 30 | + . "$NVM_DIR/nvm.sh" |
| 31 | + return 0 |
| 32 | + fi |
| 33 | + return 1 |
| 34 | +} |
| 35 | + |
| 36 | +install_node_via_nvm() { |
| 37 | + info "Node.js not found. Installing nvm (${NVM_VERSION}) and Node.js 24." |
| 38 | + if ! require_cmd curl && ! require_cmd wget; then |
| 39 | + error "Need curl or wget to install nvm. Install one of them and re-run this script." |
| 40 | + fi |
| 41 | + |
| 42 | + if [ ! -d "$HOME/.nvm" ]; then |
| 43 | + local install_url="https://raw.githubusercontent.com/nvm-sh/nvm/${NVM_VERSION}/install.sh" |
| 44 | + if require_cmd curl; then |
| 45 | + curl -fsSL "$install_url" | bash || error "Failed to install nvm." |
| 46 | + else |
| 47 | + wget -qO- "$install_url" | bash || error "Failed to install nvm." |
| 48 | + fi |
| 49 | + else |
| 50 | + info "nvm is already present at ${HOME}/.nvm" |
| 51 | + fi |
| 52 | + |
| 53 | + ensure_nvm_loaded || error "nvm was installed but nvm.sh could not be loaded from ${NVM_DIR}/nvm.sh." |
| 54 | + |
| 55 | + nvm install 24 || error "nvm failed to install Node.js 24." |
| 56 | + nvm use 24 || error "nvm failed to activate Node.js 24." |
| 57 | + nvm alias default 24 2>/dev/null || true |
| 58 | + |
| 59 | + info "Node.js $(node --version) and npm $(npm --version) are ready (npm ships with this Node release)." |
| 60 | +} |
| 61 | + |
| 62 | +ensure_node() { |
| 63 | + if require_cmd node; then |
| 64 | + info "Node.js is already installed: $(command -v node) ($(node --version))" |
| 65 | + return 0 |
| 66 | + fi |
| 67 | + install_node_via_nvm |
| 68 | +} |
| 69 | + |
| 70 | +ensure_nvm_in_path_for_npm_globals() { |
| 71 | + # If node came from nvm but this shell never sourced nvm, try to load it. |
| 72 | + if ! require_cmd node; then |
| 73 | + ensure_nvm_loaded && nvm use default >/dev/null 2>&1 || true |
| 74 | + fi |
| 75 | + if require_cmd node; then |
| 76 | + return 0 |
| 77 | + fi |
| 78 | + error "Node.js is not available in PATH after setup." |
| 79 | +} |
| 80 | + |
| 81 | +install_gh_macos() { |
| 82 | + if require_cmd brew; then |
| 83 | + info "Installing GitHub CLI with Homebrew." |
| 84 | + brew install gh || error "Homebrew failed to install gh. See messages above." |
| 85 | + return 0 |
| 86 | + fi |
| 87 | + error "GitHub CLI is not installed and Homebrew was not found. Install Homebrew from https://brew.sh then re-run, or install gh manually from https://cli.github.com/." |
| 88 | +} |
| 89 | + |
| 90 | +install_gh_linux_apt() { |
| 91 | + info "Installing GitHub CLI with apt (Debian/Ubuntu)." |
| 92 | + require_cmd sudo || error "sudo is required to install packages with apt." |
| 93 | + sudo apt-get update -y || error "apt-get update failed." |
| 94 | + if ! require_cmd curl; then |
| 95 | + sudo apt-get install -y curl || error "Failed to install curl (needed for GitHub CLI apt setup)." |
| 96 | + fi |
| 97 | + sudo install -d -m 755 /etc/apt/keyrings |
| 98 | + curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | |
| 99 | + sudo tee /etc/apt/keyrings/githubcli-archive-keyring.gpg >/dev/null || error "Failed to add GitHub CLI apt key." |
| 100 | + sudo chmod go+r /etc/apt/keyrings/githubcli-archive-keyring.gpg |
| 101 | + echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | |
| 102 | + sudo tee /etc/apt/sources.list.d/github-cli.list >/dev/null || error "Failed to add GitHub CLI apt source." |
| 103 | + sudo apt-get update -y || error "apt-get update failed after adding GitHub CLI source." |
| 104 | + sudo apt-get install -y gh || error "apt failed to install gh." |
| 105 | +} |
| 106 | + |
| 107 | +install_gh_linux_dnf() { |
| 108 | + info "Installing GitHub CLI with dnf (Fedora/RHEL-compatible)." |
| 109 | + require_cmd sudo || error "sudo is required to install packages with dnf." |
| 110 | + sudo dnf install -y 'dnf-command(config-manager)' || warn "dnf-command(config-manager) may already be installed; continuing." |
| 111 | + sudo dnf config-manager --add-repo https://cli.github.com/packages/rpm/gh-cli.repo || error "Failed to add gh dnf repository." |
| 112 | + sudo dnf install -y gh || error "dnf failed to install gh." |
| 113 | +} |
| 114 | + |
| 115 | +install_gh_linux_yum() { |
| 116 | + info "Installing GitHub CLI with yum (older RHEL/CentOS)." |
| 117 | + require_cmd sudo || error "sudo is required to install packages with yum." |
| 118 | + sudo yum install -y yum-utils || error "yum-utils installation failed." |
| 119 | + sudo yum-config-manager --add-repo https://cli.github.com/packages/rpm/gh-cli.repo || error "Failed to add gh yum repository." |
| 120 | + sudo yum install -y gh || error "yum failed to install gh." |
| 121 | +} |
| 122 | + |
| 123 | +install_gh_linux_pacman() { |
| 124 | + info "Installing GitHub CLI with pacman (Arch)." |
| 125 | + require_cmd sudo || error "sudo is required to install packages with pacman." |
| 126 | + sudo pacman -Sy --noconfirm github-cli || error "pacman failed to install github-cli." |
| 127 | +} |
| 128 | + |
| 129 | +install_gh_linux_zypper() { |
| 130 | + info "Installing GitHub CLI with zypper (openSUSE)." |
| 131 | + require_cmd sudo || error "sudo is required to install packages with zypper." |
| 132 | + sudo zypper refresh |
| 133 | + sudo zypper install -y gh || error "zypper failed to install gh." |
| 134 | +} |
| 135 | + |
| 136 | +install_gh_linux_apk() { |
| 137 | + info "Installing GitHub CLI with apk (Alpine)." |
| 138 | + require_cmd sudo || error "sudo is required to install packages with apk." |
| 139 | + sudo apk add --no-cache github-cli || error "apk failed to install github-cli." |
| 140 | +} |
| 141 | + |
| 142 | +install_gh_linux() { |
| 143 | + if [ ! -r /etc/os-release ]; then |
| 144 | + error "Cannot read /etc/os-release. Install gh manually: https://cli.github.com/manual/installation" |
| 145 | + fi |
| 146 | + # shellcheck source=/dev/null |
| 147 | + . /etc/os-release |
| 148 | + local id_lc |
| 149 | + id_lc="$(printf '%s' "${ID:-unknown}" | tr '[:upper:]' '[:lower:]')" |
| 150 | + |
| 151 | + case "$id_lc" in |
| 152 | + ubuntu | debian | linuxmint | pop | elementary | zorin | kali) |
| 153 | + install_gh_linux_apt |
| 154 | + ;; |
| 155 | + fedora | nobara | ultramarine) |
| 156 | + install_gh_linux_dnf |
| 157 | + ;; |
| 158 | + rhel | centos | rocky | almalinux) |
| 159 | + if require_cmd dnf; then |
| 160 | + install_gh_linux_dnf |
| 161 | + else |
| 162 | + install_gh_linux_yum |
| 163 | + fi |
| 164 | + ;; |
| 165 | + arch | manjaro | endeavouros) |
| 166 | + install_gh_linux_pacman |
| 167 | + ;; |
| 168 | + opensuse-tumbleweed | opensuse-leap | sled | sles) |
| 169 | + install_gh_linux_zypper |
| 170 | + ;; |
| 171 | + alpine) |
| 172 | + install_gh_linux_apk |
| 173 | + ;; |
| 174 | + *) |
| 175 | + if printf '%s' "${ID_LIKE:-}" | tr '[:upper:]' '[:lower:]' | grep -qE '(debian|ubuntu)'; then |
| 176 | + install_gh_linux_apt |
| 177 | + elif printf '%s' "${ID_LIKE:-}" | tr '[:upper:]' '[:lower:]' | grep -q 'fedora'; then |
| 178 | + install_gh_linux_dnf |
| 179 | + elif printf '%s' "${ID_LIKE:-}" | tr '[:upper:]' '[:lower:]' | grep -q 'rhel\|centos'; then |
| 180 | + if require_cmd dnf; then |
| 181 | + install_gh_linux_dnf |
| 182 | + else |
| 183 | + install_gh_linux_yum |
| 184 | + fi |
| 185 | + else |
| 186 | + error "Unsupported Linux distribution: ${ID:-unknown}. Install gh manually from https://cli.github.com/manual/installation" |
| 187 | + fi |
| 188 | + ;; |
| 189 | + esac |
| 190 | +} |
| 191 | + |
| 192 | +ensure_gh() { |
| 193 | + if require_cmd gh; then |
| 194 | + info "GitHub CLI is already installed: $(command -v gh) ($(gh --version 2>/dev/null | head -n1 || echo 'version unknown'))" |
| 195 | + return 0 |
| 196 | + fi |
| 197 | + |
| 198 | + case "$(uname -s)" in |
| 199 | + Darwin) |
| 200 | + install_gh_macos |
| 201 | + ;; |
| 202 | + Linux) |
| 203 | + install_gh_linux |
| 204 | + ;; |
| 205 | + *) |
| 206 | + error "Unsupported OS: $(uname -s). Install gh manually from https://cli.github.com/." |
| 207 | + ;; |
| 208 | + esac |
| 209 | +} |
| 210 | + |
| 211 | +enable_corepack_step() { |
| 212 | + info "Enabling Corepack." |
| 213 | + corepack enable || error "corepack enable failed. Ensure Node.js is recent enough (16.9+) and try again." |
| 214 | +} |
| 215 | + |
| 216 | +install_patternfly_cli() { |
| 217 | + info "Installing @patternfly/patternfly-cli globally from npm." |
| 218 | + npm install -g @patternfly/patternfly-cli || error "npm failed to install @patternfly/patternfly-cli globally. Check permissions and your network." |
| 219 | +} |
| 220 | + |
| 221 | +main() { |
| 222 | + info "Starting PatternFly CLI environment setup." |
| 223 | + ensure_node |
| 224 | + ensure_nvm_in_path_for_npm_globals |
| 225 | + enable_corepack_step |
| 226 | + ensure_gh |
| 227 | + install_patternfly_cli |
| 228 | + |
| 229 | + printf '\n' |
| 230 | + printf 'SUCCESS: PatternFly CLI is installed.\n' |
| 231 | + printf '\n' |
| 232 | + printf 'Run the CLI with:\n' |
| 233 | + printf ' patternfly-cli --help\n' |
| 234 | + printf '\n' |
| 235 | + printf 'If you just installed nvm, open a new terminal or run:\n' |
| 236 | + printf ' export NVM_DIR="$HOME/.nvm" && [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"\n' |
| 237 | + printf '\n' |
| 238 | +} |
| 239 | + |
| 240 | +main "$@" |
0 commit comments