feat(bash)!: hand off interactive login shells to zsh when available - #139
github-actions[bot] wants to merge 1 commit into
Conversation
The passwd login-shell entry stays `bash` on every host: bash is the only shell guaranteed to exist on macOS (3.2), Fedora (5.x), and container/rescue images. Anything that reads the entry directly (sshd for git/rsync/sftp, cron, `su`) keeps working. When zsh is on PATH, dot_bash_profile.tmpl now execs zsh -l for interactive login sessions and exports SHELL=<resolved-zsh-path> first so the running session reports the truth. Non-interactive login shells (`bash -l -c ...`, ssh-based tooling) stay in bash because the handoff is gated on `[[ $- == *i* ]]`. `bash --noprofile -i` skips .bash_profile entirely and is the sanctioned escape hatch when a real interactive bash is intended. PATH bootstrap moves from dot_bashrc.tmpl to dot_shellrc.d/01-env.sh so the bash -> zsh handoff (which never reaches .bashrc) still inherits $HOME/bin and $HOME/.local/bin on first exec. The env file is POSIX-portable so bash 3.2 and zsh 5.x see identical PATH handling. On macOS, dot_bash_profile.tmpl also exports BASH_SILENCE_DEPRECATION_WARNING=1 to suppress Apple's login nag. Closes #87 Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
|
I really need to think about this one. How often do I really want to do this when I can just exec zsh? In what scenarios will I do this? @droid what do you think? |
|
Droid finished @ahjota's task —— View job Note The code review model Two actionable issues found in PR #139:
Both are straightforward fixes; |
| # POSIX `case` keeps the file portable across bash 3.2 and zsh 5.x | ||
| # without depending on bash's [[ =~ ]] regex match. Idempotent: reruns | ||
| # are no-ops when the directory is already on PATH. | ||
| case ":$PATH:" in |
There was a problem hiding this comment.
[P2] PATH prepend order reversed, changing binary precedence
The two separate case blocks prepend $HOME/.local/bin first and then $HOME/bin, so when both directories are absent from PATH the result is $HOME/bin:$HOME/.local/bin:.... The original dot_bashrc.tmpl always put $HOME/.local/bin before $HOME/bin, so a binary present in both directories now resolves to the ~/bin copy instead of ~/.local/bin. Preserve the original order with a single combined prepend.
| case ":$PATH:" in | |
| # PATH bootstrap — prepend $HOME/.local/bin and $HOME/bin so both bash | |
| # and zsh sessions (including the bash -> zsh handoff path, which never | |
| # reaches dot_bashrc.tmpl) start with the user-local bins available. | |
| # POSIX `case` keeps the file portable across bash 3.2 and zsh 5.x | |
| # without depending on bash's [[ =~ ]] regex match. Idempotent: reruns | |
| # are no-ops when the directories are already on PATH in this order. | |
| case ":$PATH:" in | |
| *":$HOME/.local/bin:$HOME/bin:"*) ;; | |
| *) PATH="$HOME/.local/bin:$HOME/bin:$PATH" ;; | |
| esac | |
| export PATH |
| # or: sudo apt install zsh # Fedora / Debian | ||
| # When zsh is on PATH, interactive login bash sessions hand off to it | ||
| # automatically (dot_bash_profile.tmpl). The passwd login-shell entry | ||
| # stays bash so non-interactive tooling (sshd/cron/su) keeps working. |
There was a problem hiding this comment.
[P2] Incorrect package manager for Fedora in zsh install example
The added fallback comment sudo apt install zsh # Fedora / Debian is wrong for Fedora: Fedora uses dnf (or yum), not apt. A Fedora user copying that line will get a command-not-found error. Split the two distributions, e.g. # Debian / Ubuntu: sudo apt install zsh and # Fedora: sudo dnf install zsh.
Automated fix attempt
This PR was generated by the
droid-issue-fixerGitHub Action, which runsdroid execheadlessly to attempt an open issue.Closes #87
Droid exec summary
Picked issue #87 — feat(bash)!: hand off interactive login shells to zsh when available because it has the most explicit, testable acceptance criteria, all required validators (
bash -n,shellcheck,chezmoi execute-template) are on this runner, and the change is localized to four files.Branch:
droid/ghi87-bash-to-zsh-handoffCommit:
735e92a— feat(bash)!: hand off interactive login shells to zsh when availableWhat changed
dot_bash_profile.tmpl— replaced the single.bashrcsource line with a handoff-first block.[[ $- == *i* ]] && command -v zshchecks interactive + zsh on PATH, thenexec zsh -lafter exportingSHELL=<resolved zsh path>. macOS-only block exportsBASH_SILENCE_DEPRECATION_WARNING=1. Falls through to source.bashrconly on the no-handoff path.dot_bashrc.tmpl— removed the$HOME/.local/bin:$HOME/binPATH bootstrap (replaced with a comment pointing at01-env.sh).dot_shellrc.d/01-env.sh— prepended$HOME/.local/binand$HOME/bintoPATHusing POSIXcaseso the same prepend applies to bash and (post-handoff) zsh.SOURCED_BASHRCmarker test confirms idempotency.README.md— added an "Interactive Shell, zsh" entry to the Recommended list citing chore: mark req/rec/opt dependencies #80, withbrew install zsh/apt install zshcommands and a note about the passwd entry staying bash.Validation passed
chezmoi execute-templaterendered all three.tmplfiles cleanly.bash -non rendereddot_bash_profile,dot_bashrc,01-env.sh— all OK.shellcheckon the rendereddot_bash_profileproduces only the same SC2148/SC1090 warnings the existingdot_bashrc.tmplalready has (informational, accepted repo-wide)./tmp/dotfiles-sandbox:bash -l -c '…'with no zsh on PATH → stays in bash,.bashrcsourced (correct).bash -l -c '…'with fake zsh on PATH and-i-flag missing → stays in bash (correct:[[ $- == *i* ]]false).bash --login -iwith fake zsh on PATH →FAKE_ZSH_RAN=1, SHELL=/tmp/fake-zsh-bin/zsh,.bashrcis not sourced (handoff path bypass — matches the ACbash -xlitrace guarantee).bash --login -i -xtrace showscommand -v zsh → exec zsh -las the final commands;.bashrclines are absent from the trace.bash --noprofile --norc -i→ neither.bash_profilenor.bashrcis sourced (sanctioned escape hatch works).01-env.shbootstraps$HOME/binand$HOME/.local/binidempotently in both bash anddash(POSIX portability).Acceptance criteria status
$SHELL=<resolved-zsh-path>FAKE_ZSH_SHELL=/tmp/fake-zsh-bin/zsh); macOS bash 3.2 cross-host check would require a macOS runner.bash -l -c '…'stays in bash~/.bashrc(no.bashrcinbash -xlitrace)bash --noprofile -iyields interactive bash, no handoffdot_shellrc.d/10-env.sh; post-handoff zsh inherits$HOME/binand$HOME/.local/bin01-env.shruns in both shells; cross-rendered ENV/01-env.sh shows both dirs prepended).bash -npasses on rendered templateREADME.mddiff).Closes #87, body wrapped at 72.