Skip to content

Instantly share code, notes, and snippets.

@prabhatsdp
Created February 27, 2026 11:31
Show Gist options
  • Select an option

  • Save prabhatsdp/efc10a9b1adde9c0f9a0601744648b6b to your computer and use it in GitHub Desktop.

Select an option

Save prabhatsdp/efc10a9b1adde9c0f9a0601744648b6b to your computer and use it in GitHub Desktop.
Project-agnostic Flutter CLI (Zsh): standardizes flutter run and flutter build with UAT/PROD selection, flavor mapping, optional DEV_TOOLS dart-define, debug/release mode, interactive -a prompts, clear emoji logging, and forwarding of extra Flutter arguments (device, no-codesign, target file, etc.).
# ============================================================================
# Flurry CLI for Flutter (Zsh)
# ----------------------------------------------------------------------------
# A small, friendly CLI wrapper around `flutter run` and `flutter build` that:
# βœ… Keeps ENV and Flutter flavor in sync (UAT <-> uat, PROD <-> prod)
# βœ… Supports interactive mode (-a / --ask)
# βœ… Enables DEV_TOOLS only when explicitly requested (--dev)
# βœ… Defaults safely (UAT + debug) with clear logs
# βœ… Forwards extra args to Flutter commands (device, no-codesign, etc.)
#
# Installation
# ------------
# 1) Create a file:
# ~/.flurry-cli.zsh
# 2) Paste this entire script in it
# 3) Source it from your ~/.zshrc OR ~/.zsh_functions:
# [[ -f "$HOME/.flurry-cli.zsh" ]] && source "$HOME/.flurry-cli.zsh"
# 4) Reload:
# source ~/.zshrc
#
# Usage (Quick)
# -------------
# ▢️ Run:
# flurry run # default: UAT + debug
# flurry run --prod # PROD + debug
# flurry run --uat --release # UAT + release
# flurry run --prod --dev --release # PROD + dev tools + release
# flurry run --prod -d emulator-5554 # forward device to flutter run
#
# 🧩 Interactive run:
# flurry run -a
#
# πŸ—οΈ Build:
# flurry build # default: apk + UAT + debug
# flurry build --ios --release # ios release, UAT by default
# flurry build --prod --appbundle --release
# flurry build --ios --release --no-codesign # forwarded args
#
# 🧩 Interactive build:
# flurry build -a
#
# Flags Summary
# -------------
# ENV + Flavor (always same):
# --uat => ENV=UAT + --flavor uat
# --prod => ENV=PROD + --flavor prod
# Default if none passed:
# ENV=UAT + --flavor uat (prints ℹ️ message)
#
# DEV_TOOLS:
# --dev => adds --dart-define=DEV_TOOLS=true
# absent => DEV_TOOLS is NOT passed at all (app handles default)
#
# Mode:
# --debug / --release
# absent => debug (silent)
#
# Build targets (choose one):
# --apk | --appbundle | --ios | --ipa | --web | --macos | --windows | --linux
# Default if none passed:
# apk
# ============================================================================
flurry() {
# ---------------------------
# Subcommand parsing (zsh-safe)
# ---------------------------
local sub=""
if [[ $# -ge 1 ]]; then
sub="$1"
shift
else
sub=""
fi
# ---------- shared helpers ----------
_to_upper() { printf '%s' "$1" | tr '[:lower:]' '[:upper:]'; }
_to_lower() { printf '%s' "$1" | tr '[:upper:]' '[:lower:]'; }
# Map ENV -> Flutter flavor (lowercase)
_env_to_flavor() {
case "$1" in
PROD) echo "prod" ;;
UAT) echo "uat" ;;
*) echo "uat" ;; # safe fallback
esac
}
# ---------- zsh-safe interactive prompts ----------
_ask_env() {
local def="$1" ans=""
while true; do
read -r "?🧩 ENV (uat/prod) [${def}]: " ans
ans="${ans:-$def}"
ans="$(_to_upper "$ans")"
case "$ans" in
UAT|PROD) echo "$ans"; return 0 ;;
*) echo "❌ Invalid ENV. Enter 'uat' or 'prod'." ;;
esac
done
}
_ask_bool() {
local prompt="$1" def="$2" ans=""
while true; do
read -r "?🧩 ${prompt} [${def}]: " ans
ans="${ans:-$def}"
ans="$(_to_lower "$ans")"
case "$ans" in
y|yes|true|1) echo "true"; return 0 ;;
n|no|false|0) echo "false"; return 0 ;;
*) echo "❌ Invalid input. Use y/n or true/false." ;;
esac
done
}
_ask_mode() {
local def="$1" ans=""
while true; do
read -r "?🧩 Mode (debug/release) [${def}]: " ans
ans="${ans:-$def}"
ans="$(_to_lower "$ans")"
case "$ans" in
debug|release) echo "$ans"; return 0 ;;
*) echo "❌ Invalid mode. Enter 'debug' or 'release'." ;;
esac
done
}
_ask_build_target() {
local def="$1" ans=""
echo
echo "🧩 Build targets: ios | ipa | apk | appbundle | macos | windows | linux | web"
while true; do
read -r "?🧩 Target [${def}]: " ans
ans="${ans:-$def}"
ans="$(_to_lower "$ans")"
case "$ans" in
ios|ipa|apk|appbundle|macos|windows|linux|web) echo "$ans"; return 0 ;;
*) echo "❌ Invalid target. Pick one from the list above." ;;
esac
done
}
_print_main_help() {
cat <<'HELP'
πŸ“Œ flurry <command> [options]
Commands:
run ▢️ flutter run ...
build πŸ—οΈ flutter build ...
Try:
flurry run --help
flurry build --help
HELP
}
case "$sub" in
# ==========================================================
# RUN
# ==========================================================
run)
local env="" dev_flag=0 mode="" ask_mode=0 show_help=0
local extra_args=()
while [[ $# -gt 0 ]]; do
case "$1" in
-a|--ask) ask_mode=1 ;;
--prod) env="PROD" ;;
--uat) env="UAT" ;;
--dev) dev_flag=1 ;;
--release) mode="release" ;;
--debug) mode="debug" ;;
-h|--help) show_help=1 ;;
*) extra_args+=("$1") ;;
esac
shift
done
if [[ $show_help -eq 1 ]]; then
cat <<'HELP'
▢️ flurry run [--prod|--uat] [--dev] [--release|--debug] [...extra flutter run args]
▢️ flurry run -a | --ask
Defaults:
🌍 ENV/flavor : UAT/uat (if not provided) + info message
🐞 Mode : debug (if not provided)
🧰 DEV_TOOLS : enabled only if --dev is present (otherwise not passed)
Examples:
flurry run
flurry run --prod --release
flurry run --uat --dev
flurry run -a
flurry run --prod -d emulator-5554
HELP
return 0
fi
if [[ $ask_mode -eq 1 ]]; then
echo
echo "🧩 Interactive mode: RUN"
echo "----------------------"
env="$(_ask_env "${env:-UAT}")"
mode="$(_ask_mode "${mode:-debug}")"
local dev_ans
dev_ans="$(_ask_bool "Enable DEV_TOOLS? (y/n or true/false)" "$([[ $dev_flag -eq 1 ]] && echo true || echo false)")"
[[ "$dev_ans" == "true" ]] && dev_flag=1 || dev_flag=0
fi
if [[ -z "$env" ]]; then
env="UAT"
echo "ℹ️ ENV not provided β†’ defaulting to UAT (ENV=UAT, flavor=uat). Use --prod for PROD."
fi
[[ -z "$mode" ]] && mode="debug"
local flavor="$(_env_to_flavor "$env")"
local cmd_arr=(flutter run "--$mode" --flavor "$flavor" --dart-define=ENV="$env")
[[ $dev_flag -eq 1 ]] && cmd_arr+=(--dart-define=DEV_TOOLS=true)
[[ ${#extra_args[@]} -gt 0 ]] && cmd_arr+=("${extra_args[@]}")
echo
echo "βœ… Running Flutter:"
echo " ${cmd_arr[*]}"
echo
"${cmd_arr[@]}"
;;
# ==========================================================
# BUILD
# ==========================================================
build)
local env="" dev_flag=0 mode="" ask_mode=0 show_help=0
local target=""
local extra_args=()
while [[ $# -gt 0 ]]; do
case "$1" in
-a|--ask) ask_mode=1 ;;
--prod) env="PROD" ;;
--uat) env="UAT" ;;
--dev) dev_flag=1 ;;
--release) mode="release" ;;
--debug) mode="debug" ;;
--ios) target="ios" ;;
--ipa) target="ipa" ;;
--apk) target="apk" ;;
--appbundle) target="appbundle" ;;
--macos) target="macos" ;;
--windows) target="windows" ;;
--linux) target="linux" ;;
--web) target="web" ;;
-h|--help) show_help=1 ;;
*) extra_args+=("$1") ;;
esac
shift
done
if [[ $show_help -eq 1 ]]; then
cat <<'HELP'
πŸ—οΈ flurry build [--prod|--uat] [--dev] [--release|--debug] [target] [...extra flutter build args]
πŸ—οΈ flurry build -a | --ask
Targets:
--ios | --ipa | --apk | --appbundle | --macos | --windows | --linux | --web
Defaults:
🌍 ENV/flavor : UAT/uat (if not provided) + info message
🐞 Mode : debug (if not provided)
🧰 DEV_TOOLS : enabled only if --dev is present (otherwise not passed)
🎯 Target : apk (if not provided)
Examples:
flurry build
flurry build --uat --apk
flurry build --prod --appbundle --release
flurry build --ios --release --no-codesign
flurry build -a
HELP
return 0
fi
if [[ $ask_mode -eq 1 ]]; then
echo
echo "🧩 Interactive mode: BUILD"
echo "------------------------"
target="$(_ask_build_target "${target:-apk}")"
env="$(_ask_env "${env:-UAT}")"
mode="$(_ask_mode "${mode:-debug}")"
local dev_ans
dev_ans="$(_ask_bool "Enable DEV_TOOLS? (y/n or true/false)" "$([[ $dev_flag -eq 1 ]] && echo true || echo false)")"
[[ "$dev_ans" == "true" ]] && dev_flag=1 || dev_flag=0
fi
if [[ -z "$env" ]]; then
env="UAT"
echo "ℹ️ ENV not provided β†’ defaulting to UAT (ENV=UAT, flavor=uat). Use --prod for PROD."
fi
[[ -z "$mode" ]] && mode="debug"
[[ -z "$target" ]] && target="apk"
local flavor="$(_env_to_flavor "$env")"
local cmd_arr=(flutter build "$target" "--$mode" --flavor "$flavor" --dart-define=ENV="$env")
[[ $dev_flag -eq 1 ]] && cmd_arr+=(--dart-define=DEV_TOOLS=true)
[[ ${#extra_args[@]} -gt 0 ]] && cmd_arr+=("${extra_args[@]}")
echo
echo "βœ… Building Flutter:"
echo " ${cmd_arr[*]}"
echo
"${cmd_arr[@]}"
;;
""|help|-h|--help)
_print_main_help
;;
*)
echo "❌ Unknown command: '$sub'"
echo "ℹ️ Available commands: run, build"
echo "πŸ‘‰ Try: flurry --help"
return 2
;;
esac
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment