Created
February 27, 2026 11:31
-
-
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.).
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
| # ============================================================================ | |
| # 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