Last active
September 22, 2025 13:24
-
-
Save carlovsk/ad4d602137cf9cf213c0103fae85cdec to your computer and use it in GitHub Desktop.
Setup MacBook
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # ----------------------------------------------------------------------------- | |
| # setup_dev_env_mac.sh | |
| # ----------------------------------------------------------------------------- | |
| # Automated bootstrap script for a fresh Apple‑Silicon MacBook (M1–M4) | |
| # Installs and configures: | |
| # • Xcode Command‑Line Tools (prerequisite) | |
| # • Homebrew | |
| # • Docker Desktop | |
| # • fnm (Fast Node Manager) + latest LTS Node.js | |
| # • pnpm via Corepack | |
| # • Python 3 (brew) | |
| # • Oh My Zsh (unattended) | |
| # ----------------------------------------------------------------------------- | |
| # Usage | |
| # curl -fsSL https://example.com/setup_dev_env_mac_m4.sh | bash | |
| # or | |
| # chmod +x setup_dev_env_mac_m4.sh && ./setup_dev_env_mac_m4.sh | |
| # ----------------------------------------------------------------------------- | |
| set -euo pipefail | |
| # Colors for pretty output | |
| GREEN="\033[0;32m"; YELLOW="\033[1;33m"; RED="\033[0;31m"; NC="\033[0m" | |
| log() { printf "${GREEN}[✔] %s${NC}\n" "$1"; } | |
| warn() { printf "${YELLOW}[!] %s${NC}\n" "$1"; } | |
| fail() { printf "${RED}[✖] %s${NC}\n" "$1"; exit 1; } | |
| # ----------------------------------------------------------------------------- | |
| # 1. Xcode Command‑Line Tools --------------------------------------------------- | |
| # ----------------------------------------------------------------------------- | |
| if ! xcode-select -p >/dev/null 2>&1; then | |
| warn "Installing Xcode Command‑Line Tools … (this may pop up a GUI prompt)" | |
| xcode-select --install || true | |
| echo "After the installation finishes, re‑run this script." | |
| exit 0 | |
| else | |
| log "Xcode Command‑Line Tools already installed" | |
| fi | |
| # ----------------------------------------------------------------------------- | |
| # 2. Homebrew ------------------------------------------------------------------ | |
| # ----------------------------------------------------------------------------- | |
| if ! command -v brew >/dev/null 2>&1; then | |
| warn "Installing Homebrew …" | |
| NONINTERACTIVE=1 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" | |
| echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> "$HOME/.zprofile" | |
| eval "$(/opt/homebrew/bin/brew shellenv)" | |
| log "Homebrew installed" | |
| else | |
| log "Homebrew already installed" | |
| fi | |
| # Update & upgrade | |
| brew update && brew upgrade | |
| # ----------------------------------------------------------------------------- | |
| # 3. Core packages -------------------------------------------------------------- | |
| # ----------------------------------------------------------------------------- | |
| PACKAGE_LIST=(git wget curl python@3.12 fnm corepack) | |
| for pkg in "${PACKAGE_LIST[@]}"; do | |
| if brew list "$pkg" >/dev/null 2>&1; then | |
| log "$pkg already installed" | |
| else | |
| brew install "$pkg" | |
| fi | |
| done | |
| # ----------------------------------------------------------------------------- | |
| # 4. Docker Desktop ------------------------------------------------------------- | |
| # ----------------------------------------------------------------------------- | |
| if ! brew list --cask docker >/dev/null 2>&1; then | |
| warn "Installing Docker Desktop (cask) …" | |
| brew install --cask docker | |
| log "Docker Desktop installed – launch it once to finish setup" | |
| else | |
| log "Docker Desktop already installed" | |
| fi | |
| # ----------------------------------------------------------------------------- | |
| # 5. FNM & Node.js -------------------------------------------------------------- | |
| # ----------------------------------------------------------------------------- | |
| if ! grep -q "fnm env" "$HOME/.zshrc" 2>/dev/null; then | |
| echo '# >>> fnm setup >>>' >> "$HOME/.zshrc" | |
| echo 'eval "$(fnm env --use-on-cd)"' >> "$HOME/.zshrc" | |
| echo '# <<< fnm setup <<<' >> "$HOME/.zshrc" | |
| log "Added fnm init to ~/.zshrc" | |
| fi | |
| # Ensure current shell knows fnm | |
| export PATH="$HOME/Library/Application Support/fnm:$PATH" | |
| eval "$(fnm env)" | |
| # Install latest LTS Node | |
| LATEST_LTS=$(fnm ls-remote --latest) | |
| if fnm list | grep -q "$LATEST_LTS"; then | |
| log "Node $LATEST_LTS already installed via fnm" | |
| else | |
| warn "Installing Node $LATEST_LTS with fnm …" | |
| fnm install "$LATEST_LTS" | |
| fi | |
| fnm default "$LATEST_LTS" | |
| # ----------------------------------------------------------------------------- | |
| # 6. pnpm via Corepack ---------------------------------------------------------- | |
| # ----------------------------------------------------------------------------- | |
| corepack enable | |
| auth_pnpm_version=$(corepack ls | grep pnpm | awk '{print $2}') || true | |
| if [[ -z "$auth_pnpm_version" ]]; then | |
| warn "Preparing latest pnpm with Corepack …" | |
| corepack prepare pnpm@latest --activate | |
| log "pnpm ready (Corepack)" | |
| else | |
| log "pnpm ${auth_pnpm_version} already active via Corepack" | |
| fi | |
| # ----------------------------------------------------------------------------- | |
| # 7. Python 3 symlink ----------------------------------------------------------- | |
| # ----------------------------------------------------------------------------- | |
| if ! command -v python3 >/dev/null 2>&1; then | |
| brew link --overwrite python@3.12 | |
| fi | |
| log "Python $(python3 --version) available" | |
| # ----------------------------------------------------------------------------- | |
| # 8. Oh My Zsh ----------------------------------------------------------------- | |
| # ----------------------------------------------------------------------------- | |
| if [[ ! -d "$HOME/.oh-my-zsh" ]]; then | |
| warn "Installing Oh My Zsh …" | |
| RUNZSH=no KEEP_ZSHRC=yes CHSH=no /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" | |
| log "Oh My Zsh installed" | |
| else | |
| log "Oh My Zsh already installed" | |
| fi | |
| # ----------------------------------------------------------------------------- | |
| # 9. Finishing up --------------------------------------------------------------- | |
| # ----------------------------------------------------------------------------- | |
| log "Developer environment ready! 🚀" | |
| log "➡ Open a new terminal session or run 'source ~/.zshrc' to load the updates." | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment