Phase 2: Chezmoi dotfile orchestration + fastfetch

This commit is contained in:
Travis Herbranson 2026-04-23 12:40:21 -04:00
parent ac7e575957
commit f554eb8901
7 changed files with 157 additions and 8 deletions

View File

@ -1,10 +1,11 @@
# CLI Standardization
Ansible project to deploy a modern CLI environment (Fish + Starship + modern coreutils)
to Arch and Ubuntu/Debian hosts.
to Arch and Ubuntu/Debian hosts. Includes optional Chezmoi dotfile orchestration.
## What it installs
**Phase 1 — packages and config templates:**
- **Fish shell** 4.x (PPA on Ubuntu, pacman on Arch)
- **Starship** prompt (official binary installer)
- **fzf** — fuzzy finder
@ -13,8 +14,14 @@ to Arch and Ubuntu/Debian hosts.
- **eza** — modern ls
- **fd** — modern find
- **ripgrep** — fast grep
- **fastfetch** — system info on login
- **Fisher** plugin manager + plugins
**Phase 2 — Chezmoi dotfile sync (opt-in):**
- **Chezmoi** — dotfile manager synced from Gitea
- Manages: Fish config, Starship, Ghostty, Zellij
- Machine-type aware: servers skip Ghostty/Zellij configs
## Dev workflow
```bash
@ -27,9 +34,11 @@ ansible-playbook playbook.yml --syntax-check
# Dry run
ansible-playbook playbook.yml -i inventory.yml --check --diff
# Deploy
# Deploy (Phase 1 only — default)
ansible-playbook playbook.yml -i inventory.yml
ansible-playbook playbook.yml -i inventory.yml --limit manjaro-dev
# Deploy with Chezmoi (Phase 2)
ansible-playbook playbook.yml -i inventory.yml -e cli_modern_install_chezmoi=true -e cli_modern_chezmoi_repo=git@gitea:herbygitea/dotfiles.git
```
## Role structure
@ -43,15 +52,47 @@ roles/cli_modern/
│ ├── packages-debian.yml # Ubuntu/Debian packages + Fish PPA
│ ├── starship.yml # Starship binary install
│ ├── fisher.yml # Fisher + plugin sync
│ ├── config.yml # Deploy config templates
│ └── default-shell.yml # Set Fish as login shell
│ ├── config.yml # Deploy config templates (Phase 1)
│ ├── default-shell.yml # Set Fish as login shell
│ └── chezmoi.yml # Chezmoi install + apply (Phase 2)
└── templates/
├── config.fish.j2 # Fish shell config
├── starship.toml.j2 # Starship prompt config
└── fish_plugins.j2 # Fisher plugin list
```
## Dotfiles repo (Phase 2)
Separate repo at `/opt/projects/pbs-workshop/dotfiles/`, to be pushed to Gitea.
Contains placeholder configs — replace with real dotfiles before enabling Chezmoi.
```
dotfiles/
├── .chezmoi.toml.tmpl # Prompted config (name, email, machine type)
├── .chezmoiignore # Skips Ghostty/Zellij on servers
├── dot_config/
│ ├── fish/config.fish # PLACEHOLDER
│ ├── fish/fish_plugins # Fisher plugin list
│ ├── ghostty/config # PLACEHOLDER (workstations only)
│ ├── starship.toml # PLACEHOLDER
│ └── zellij/config.kdl # PLACEHOLDER (workstations only)
```
## Configuration
All options are in `roles/cli_modern/defaults/main.yml`. Override per-host
in `host_vars/` or per-group in `group_vars/`.
### Phase 1 vs Phase 2 config management
Phase 1 deploys Fish/Starship configs via Ansible templates. Phase 2 uses
Chezmoi from a Git repo. When enabling Chezmoi, set the Phase 1 template
flags to false to avoid conflicts:
```yaml
cli_modern_deploy_fish_config: false
cli_modern_deploy_starship_config: false
cli_modern_install_chezmoi: true
cli_modern_chezmoi_repo: "git@gitea:herbygitea/dotfiles.git"
cli_modern_chezmoi_machine_type: "workstation" # or "server"
```

View File

@ -37,6 +37,9 @@ cli_modern_install_fd: true
# ripgrep — fast grep
cli_modern_install_ripgrep: true
# fastfetch — system info on login (neofetch successor)
cli_modern_install_fastfetch: true
# Fisher plugin manager — auto-installed on first Fish launch
cli_modern_install_fisher: true
@ -48,6 +51,14 @@ cli_modern_fisher_plugins:
- "meaningful-ooo/sponge"
- "jorgebucaran/autopair.fish"
# Deploy config templates
# Deploy config templates (Phase 1 — Ansible-managed templates)
# Set to false when using Chezmoi (Phase 2) to avoid conflicts
cli_modern_deploy_fish_config: true
cli_modern_deploy_starship_config: true
# ── Phase 2: Chezmoi dotfile orchestration ──────────────────
cli_modern_install_chezmoi: false
# Gitea repo URL for dotfiles (SSH format)
cli_modern_chezmoi_repo: ""
# Machine type passed to chezmoi init ("workstation" or "server")
cli_modern_chezmoi_machine_type: "server"

View File

@ -0,0 +1,81 @@
---
# Phase 2: Install Chezmoi and apply dotfiles from Gitea repo.
- name: Check if Chezmoi is already installed
ansible.builtin.command: chezmoi --version
register: cli_modern_chezmoi_check
changed_when: false
failed_when: false
# --- Install Chezmoi (Arch) ---
- name: Install Chezmoi via pacman
become: true
community.general.pacman:
name: chezmoi
state: present
when:
- cli_modern_chezmoi_check.rc != 0
- ansible_os_family == "Archlinux"
# --- Install Chezmoi (Debian/Ubuntu) ---
- name: Download Chezmoi install script
ansible.builtin.get_url:
url: https://get.chezmoi.io
dest: /tmp/chezmoi-install.sh
mode: "0755"
when:
- cli_modern_chezmoi_check.rc != 0
- ansible_os_family == "Debian"
- name: Install Chezmoi via official installer
become: true
ansible.builtin.command: /tmp/chezmoi-install.sh -b /usr/local/bin
args:
creates: /usr/local/bin/chezmoi
when:
- cli_modern_chezmoi_check.rc != 0
- ansible_os_family == "Debian"
- name: Clean up Chezmoi installer
ansible.builtin.file:
path: /tmp/chezmoi-install.sh
state: absent
when:
- cli_modern_chezmoi_check.rc != 0
- ansible_os_family == "Debian"
# --- Initialize and apply dotfiles ---
- name: Check if Chezmoi is already initialized
ansible.builtin.stat:
path: "{{ cli_modern_user_home }}/.local/share/chezmoi"
register: cli_modern_chezmoi_dir
- name: Initialize Chezmoi from dotfiles repo
become: true
become_user: "{{ cli_modern_user }}"
ansible.builtin.command: >
chezmoi init {{ cli_modern_chezmoi_repo }}
--promptString "Your name={{ cli_modern_user }}"
--promptString "Your email="
--promptChoice "Machine type={{ cli_modern_chezmoi_machine_type }}"
--no-tty
args:
chdir: "{{ cli_modern_user_home }}"
creates: "{{ cli_modern_user_home }}/.local/share/chezmoi/.git"
when:
- cli_modern_chezmoi_repo | length > 0
- not cli_modern_chezmoi_dir.stat.exists
- name: Apply Chezmoi dotfiles
become: true
become_user: "{{ cli_modern_user }}"
ansible.builtin.command: chezmoi apply --no-tty
args:
chdir: "{{ cli_modern_user_home }}"
register: cli_modern_chezmoi_apply
changed_when: cli_modern_chezmoi_apply.rc == 0
when:
- cli_modern_chezmoi_repo | length > 0

View File

@ -24,3 +24,8 @@
- name: Set Fish as default shell
ansible.builtin.include_tasks: default-shell.yml
when: cli_modern_set_default_shell
# Phase 2: Chezmoi dotfile orchestration
- name: Install Chezmoi and apply dotfiles
ansible.builtin.include_tasks: chezmoi.yml
when: cli_modern_install_chezmoi

View File

@ -17,6 +17,7 @@
(['bat'] if cli_modern_install_bat else []) +
(['eza'] if cli_modern_install_eza else []) +
(['fd'] if cli_modern_install_fd else []) +
(['ripgrep'] if cli_modern_install_ripgrep else [])
(['ripgrep'] if cli_modern_install_ripgrep else []) +
(['fastfetch'] if cli_modern_install_fastfetch else [])
}}
when: cli_modern_arch_packages | length > 0

View File

@ -63,7 +63,8 @@
(['bat'] if cli_modern_install_bat else []) +
(['eza'] if cli_modern_install_eza else []) +
(['fd-find'] if cli_modern_install_fd else []) +
(['ripgrep'] if cli_modern_install_ripgrep else [])
(['ripgrep'] if cli_modern_install_ripgrep else []) +
(['fastfetch'] if cli_modern_install_fastfetch else [])
}}
when: cli_modern_deb_packages | length > 0

View File

@ -54,4 +54,13 @@ if status is-interactive
# Suppress Fish greeting
set -g fish_greeting
{% if cli_modern_install_fastfetch %}
# ── System Info ─────────────────────────────────────────
# Show machine identity on first shell in a login session.
# Skips nested shells and non-login to keep things snappy.
if status is-login
fastfetch
end
{% endif %}
end