From fbbbc2e5c48040f1463165a477ebdee2bf87d6e1 Mon Sep 17 00:00:00 2001 From: Yunsung Lee Date: Fri, 20 Mar 2026 16:43:42 +0900 Subject: [PATCH] feat: support --yolo in subcommand position for update and install Previously `dotfiles update --yolo` silently ignored the flag because --yolo was only parsed in the global option loop. Users naturally type the flag after the subcommand, matching how --fast and --skip-tools already work in both positions. Add --yolo case arms to run_update() and run_install() argument parsers, update the update help text, and add four new tests covering subcommand-position usage and flag-combination overrides. Co-Authored-By: Claude Opus 4.6 (1M context) --- bin/dotfiles | 21 +++++++++++++- tests/test_dotfiles_bin.py | 58 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 1 deletion(-) diff --git a/bin/dotfiles b/bin/dotfiles index 495e923..bad8e9a 100755 --- a/bin/dotfiles +++ b/bin/dotfiles @@ -87,6 +87,7 @@ Update options: --branch Git branch to sync from (default: \$DOTFILES_BRANCH or main) --fast Skip default agent-tool installation after syncing --no-stash Fail instead of auto-stashing local checkout changes + --yolo Full install: rich profile + all packages + all tools + auto-yes --help, -h Show this help Auto-stashed checkout changes stay in git stash for manual review/restore. @@ -189,6 +190,14 @@ run_install() { DOTFILES_SKIP_TOOLS=1 shift ;; + --yolo) + # Keep in sync with --yolo in global parser and run_update + DOTFILES_YES=1 + DOTFILES_PREFER_RICH=1 + DOTFILES_ALL_PACKAGES=1 + DOTFILES_ALL_TOOLS=1 + shift + ;; --) shift break @@ -199,7 +208,7 @@ run_install() { esac done - export DOTFILES_SKIP_APPLY DOTFILES_SKIP_TOOLS + export DOTFILES_SKIP_APPLY DOTFILES_SKIP_TOOLS DOTFILES_YES DOTFILES_PREFER_RICH DOTFILES_ALL_PACKAGES DOTFILES_ALL_TOOLS # Show banner on install (skip if already shown by run_update). if [ "${_dotfiles_banner_shown:-0}" != "1" ]; then @@ -381,6 +390,14 @@ run_update() { update_autostash=0 shift ;; + --yolo) + # Keep in sync with --yolo in global parser and run_install + DOTFILES_YES=1 + DOTFILES_PREFER_RICH=1 + DOTFILES_ALL_PACKAGES=1 + DOTFILES_ALL_TOOLS=1 + shift + ;; --help|-h) update_usage return 0 @@ -395,6 +412,8 @@ run_update() { esac done + export DOTFILES_YES DOTFILES_PREFER_RICH DOTFILES_ALL_PACKAGES DOTFILES_ALL_TOOLS + # Validate branch name contains only safe characters. case "$update_branch" in *[!a-zA-Z0-9/_.-]*) diff --git a/tests/test_dotfiles_bin.py b/tests/test_dotfiles_bin.py index a4927d9..093ffcc 100644 --- a/tests/test_dotfiles_bin.py +++ b/tests/test_dotfiles_bin.py @@ -106,6 +106,64 @@ def test_yolo_skip_tools_wins(self) -> None: self.assertIn("agent tools (--skip-tools)", completed.stdout) self.assertNotIn("ALL agent tools", completed.stdout) + def test_yolo_after_install_subcommand(self) -> None: + completed = self.run_bin("install", "--yolo", "--dry-run") + + self.assertEqual( + completed.returncode, + 0, + msg=f"install --yolo --dry-run failed\nstdout:\n{completed.stdout}\nstderr:\n{completed.stderr}", + ) + self.assertIn("ALL agent tools", completed.stdout) + self.assertIn("ALL packages", completed.stdout) + + def test_yolo_after_update_subcommand(self) -> None: + completed = self.run_bin( + "update", "--yolo", "--dry-run", + env={"DOTFILES_CHECKOUT_ALREADY_UPDATED": "1"}, + ) + + self.assertEqual( + completed.returncode, + 0, + msg=f"update --yolo --dry-run failed\nstdout:\n{completed.stdout}\nstderr:\n{completed.stderr}", + ) + self.assertIn("ALL agent tools", completed.stdout) + self.assertIn("ALL packages", completed.stdout) + + def test_yolo_skip_tools_after_install(self) -> None: + completed = self.run_bin("install", "--yolo", "--skip-tools", "--dry-run") + + self.assertEqual( + completed.returncode, + 0, + msg=( + "install --yolo --skip-tools --dry-run failed\n" + f"stdout:\n{completed.stdout}\nstderr:\n{completed.stderr}" + ), + ) + self.assertIn("agent tools (--skip-tools)", completed.stdout) + self.assertNotIn("ALL agent tools", completed.stdout) + self.assertIn("ALL packages", completed.stdout) + + def test_yolo_fast_after_update(self) -> None: + completed = self.run_bin( + "update", "--fast", "--yolo", "--dry-run", + env={"DOTFILES_CHECKOUT_ALREADY_UPDATED": "1"}, + ) + + self.assertEqual( + completed.returncode, + 0, + msg=( + "update --fast --yolo --dry-run failed\n" + f"stdout:\n{completed.stdout}\nstderr:\n{completed.stderr}" + ), + ) + self.assertIn("agent tools (--skip-tools)", completed.stdout) + self.assertNotIn("ALL agent tools", completed.stdout) + self.assertIn("ALL packages", completed.stdout) + def test_yolo_skip_apply(self) -> None: completed = self.run_bin("--yolo", "--skip-apply", "--dry-run", "install")