Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Pipeline Design 1

ezigus edited this page Feb 21, 2026 · 2 revisions

Now I have a complete picture of the codebase. Here is the ADR:


Design: Add shell completion installation to shipwright init

Context

shipwright init (scripts/sw-init.sh) already has a "Shell Completions" section (lines 387–475) that installs completions for zsh (to ~/.zsh/completions/_shipwright) and bash (to ~/.local/share/bash-completion/completions/shipwright). The repo already ships completions/shipwright.fish with full command coverage, but the init script never installs it — fish users must manually copy the file. Additionally, the existing zsh and bash installation blocks both unconditionally overwrite the target file on every run, providing no idempotency guard, which produces confusing output on repeated init runs.

Constraints:

  • All scripts must be Bash 3.2 compatible (no associative arrays, no ${var,,})
  • set -euo pipefail is in effect; any command that can fail zero-with-empty-output must be guarded with || true
  • Atomic file writes use tmp + mv; this does not apply here since completion files are copied, not generated
  • The test harness sandboxes $HOME via a temp directory — new tests must override SHELL inside invoke_init rather than mocking the fish binary
  • Fish completions auto-load from ~/.config/fish/completions/ — no .fishrc modification is needed

Decision

Extend sw-init.sh's existing shell completion section with three targeted changes:

  1. Fish detection — insert elif [[ "${SHELL:-}" == *"fish"* ]]; then SHELL_TYPE="fish" between the *"zsh"* and *"bash"* branches. Fish must be detected before bash because no fallback env variable (FISH_VERSION) exists in the wild.

  2. Fish installation block — add an elif [[ "$SHELL_TYPE" == "fish" ]] branch that copies completions/shipwright.fish to ~/.config/fish/completions/shipwright.fish. No .fishrc edit is needed; fish auto-loads all files in that directory. A pre-check guards idempotency.

  3. Idempotency guards for zsh and bash — wrap the existing copy operations in if [[ -f "$TARGET" ]]; then success "already installed — skipping"; else ...; fi blocks. The fpath/.zshrc mutation logic for zsh is kept inside the else branch since it is only needed on first install.

  4. Reload message — add a fish case to the existing $install_completions message block. Fish's message differs from zsh/bash: completions are automatic, so the message says "Completions are loaded automatically in fish" rather than prompting a source command.

Data flow:

$SHELL env var
 → SHELL_TYPE detection (zsh | fish | bash | "")
 → target dir selection
 → idempotency check (file exists?)
 → cp + chmod + success message
 → install_completions=1
 → reload instructions

Error handling: if completions/shipwright.fish is absent (e.g., a partial checkout), the block skips silently — same behavior as the existing zsh/bash blocks when their source files are missing.

Alternatives Considered

  1. Install all three completions unconditionally regardless of $SHELL — Pros: simpler code path, guarantees completions land everywhere on every machine. Cons: modifies ~/.zshrc and ~/.bashrc on fish users' machines unexpectedly; violates principle of least surprise and has been the source of complaints in similar tools (e.g., nvm). Rejected.

  2. Add a --completions subcommand / flag instead of auto-install in init — Pros: users who don't want completions are never surprised. Cons: completions are a standard part of tool installation; no existing tool in this class makes completions opt-in; the existing init already auto-installs zsh/bash completions so this would create inconsistency. Rejected.

  3. Detect fish via command -v fish — Pros: works even when $SHELL isn't set to fish. Cons: a user might have fish installed but use zsh as their default shell; we'd incorrectly install fish completions. The $SHELL env var is the correct signal for "this is my login shell". Rejected.

Implementation Plan

  • Files to create: none
  • Files to modify:
    • scripts/sw-init.sh — shell detection block (line ~392), completion installation chain (lines ~407–466), reload message block (lines ~468–475)
    • scripts/sw-init-test.sh — add 5 tests after the existing 21, register them under a new "Shell Completions" group in the run section (~line 598)
  • Dependencies: none — completions/shipwright.fish already exists in the repo
  • Risk areas:
    • The shell detection order matters: fish must be inserted between zsh and bash (not after) because some users alias bash inside fish startup files, which can affect $SHELL on misconfigured systems — early detection wins
    • The zsh idempotency change wraps a block that also mutates ~/.zshrc; the entire block (copy + fpath) must move inside the else branch, not just the cp call, otherwise a second init would skip the copy but still append to ~/.zshrc
    • invoke_init in the test harness does not pass SHELL explicitly — the sandboxed bash script inherits the test runner's $SHELL, which is almost certainly not fish. New tests must explicitly set SHELL=/usr/bin/fish (or any path containing "fish") inside the subshell invocation

Validation Criteria

  • Running init with SHELL=/usr/bin/fish produces ~/.config/fish/completions/shipwright.fish containing valid fish complete directives
  • Running init twice with SHELL=/usr/bin/fish prints "already installed — skipping" on the second run and does not overwrite the file
  • Running init twice with SHELL=/bin/zsh prints "already installed — skipping" on the second run and does not append a duplicate fpath line to ~/.zshrc
  • Running init twice with SHELL=/bin/bash prints "already installed — skipping" on the second run and does not append a duplicate source line to ~/.bashrc
  • test_fish_completions_installed passes: file exists at expected path, output contains "Installed fish completions"
  • test_zsh_completions_installed passes: file exists at ~/.zsh/completions/_shipwright
  • test_bash_completions_installed passes: file exists at ~/.local/share/bash-completion/completions/shipwright
  • test_completions_idempotent passes: second init with zsh produces exactly one fpath+=~/.zsh/completions line in ~/.zshrc
  • All 21 pre-existing sw-init-test.sh tests continue to pass (no regressions)
  • npm test exits 0 with all registered test suites passing

Clone this wiki locally

AltStyle によって変換されたページ (->オリジナル) /