CI/CD and IaC Integration Guide
CI/CD and IaC Integration Guide
Section titled “CI/CD and IaC Integration Guide”This guide covers using the dotfiles system in automated environments: CI/CD pipelines, Infrastructure as Code (IaC), container images, and configuration management tools.
Overview
Section titled “Overview”The --unattended flag enables fully automated, zero-prompt installation suitable for:
- Infrastructure as Code: Terraform, CloudFormation, Pulumi
- Container Images: Docker, Podman
- Configuration Management: Ansible, Chef, Puppet
- CI/CD Pipelines: GitHub Actions, GitLab CI, Jenkins
- VM Provisioning: Packer, Vagrant
How It Works
Section titled “How It Works”When --unattended is set:
- ✅ All interactive prompts are skipped
- ✅ Default values are used for all module configurations
- ✅ Secrets authentication is automatically skipped
- ✅ Confirmation prompts are bypassed
- ✅ Auto-detection works for non-interactive environments
The system automatically enables unattended mode when stdin is not interactive (e.g., curl | bash).
Note on example profiles. The repo ships
developer,minimal, andtest. Profile names used throughout this guide for illustration —server,ci,prod,docker,no-secrets— are not built in; create your own (a file inprofiles/, or a profile in your content overlay) or substitute a real one likeminimal.--profilealso accepts a path to a profile file.
Quick Start
Section titled “Quick Start”Basic Unattended Installation
Section titled “Basic Unattended Installation”# Using bootstrap scriptcurl -sfL https://raw.githubusercontent.com/garygentry/dotfiles/main/bootstrap.sh | bash -s -- --unattended
# Direct installationgit clone https://github.com/garygentry/dotfiles.git ~/.dotfilescd ~/.dotfilesgo build -o bin/dotfiles ../bin/dotfiles install --unattendedWith Specific Profile
Section titled “With Specific Profile”# Create config.yml before installationcat > ~/.dotfiles/config.yml <<EOFprofile: minimalsecrets: provider: noopEOF
# Run installationdotfiles install --unattendedUse Cases
Section titled “Use Cases”Terraform / AWS CloudFormation
Section titled “Terraform / AWS CloudFormation”EC2 User Data Script:
#!/bin/bashset -euo pipefail
# Install dependenciesapt-get updateapt-get install -y git golang-go
# Clone and install dotfilesexport USER=ubuntuexport HOME=/home/ubuntucd $HOMEgit clone https://github.com/garygentry/dotfiles.git .dotfilescd .dotfiles
# Build and rungo build -o bin/dotfiles ../bin/dotfiles install --unattended --profile server
# Verify installation./bin/dotfiles statusTerraform Example:
resource "aws_instance" "server" { ami = "ami-0c55b159cbfafe1f0" instance_type = "t3.micro"
user_data = <<-EOF #!/bin/bash curl -sfL https://raw.githubusercontent.com/garygentry/dotfiles/main/bootstrap.sh | \ sudo -u ubuntu bash -s -- --unattended --profile server EOF
tags = { Name = "dotfiles-provisioned-server" }}Docker Images
Section titled “Docker Images”Dockerfile Example:
FROM ubuntu:22.04
# Install dependenciesRUN apt-get update && apt-get install -y \ git \ golang-go \ curl \ && rm -rf /var/lib/apt/lists/*
# Create userRUN useradd -m -s /bin/bash developerUSER developerWORKDIR /home/developer
# Clone dotfilesRUN git clone https://github.com/garygentry/dotfiles.git .dotfilesWORKDIR /home/developer/.dotfiles
# Build CLIRUN go build -o bin/dotfiles .
# Install dotfiles in unattended modeRUN ./bin/dotfiles install --unattended --profile minimal --skip-failed
# Set PATHENV PATH="/home/developer/.dotfiles/bin:${PATH}"
CMD ["/bin/bash"]Multi-stage Build (Optimized):
# Build stageFROM golang:1.23-alpine AS builderWORKDIR /buildCOPY . .RUN go build -o dotfiles .
# Runtime stageFROM ubuntu:22.04RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/*RUN useradd -m -s /bin/bash developerUSER developerWORKDIR /home/developer
COPY --from=builder /build /home/developer/.dotfilesWORKDIR /home/developer/.dotfiles
RUN ./dotfiles install --unattended --profile docker --skip-failed
ENV PATH="/home/developer/.dotfiles/bin:${PATH}"CMD ["/bin/bash"]Ansible Playbooks
Section titled “Ansible Playbooks”Basic Playbook:
---- name: Install dotfiles hosts: servers become: yes become_user: "{{ target_user }}"
tasks: - name: Install dependencies apt: name: - git - golang-go state: present become_user: root
- name: Clone dotfiles repository git: repo: https://github.com/garygentry/dotfiles.git dest: "~/.dotfiles" version: main
- name: Build dotfiles CLI command: go build -o bin/dotfiles . args: chdir: "~/.dotfiles" creates: "~/.dotfiles/bin/dotfiles"
- name: Install dotfiles command: ./bin/dotfiles install --unattended --profile {{ dotfiles_profile | default('default') }} args: chdir: "~/.dotfiles" register: dotfiles_install changed_when: "'succeeded' in dotfiles_install.stdout"
- name: Verify installation command: ./bin/dotfiles status args: chdir: "~/.dotfiles" changed_when: falseWith Role Structure:
---- name: Ensure dependencies apt: name: [git, golang-go] state: present become: yes
- name: Clone dotfiles git: repo: "{{ dotfiles_repo }}" dest: "{{ ansible_env.HOME }}/.dotfiles" version: "{{ dotfiles_version | default('main') }}"
- name: Build CLI command: go build -o bin/dotfiles . args: chdir: "{{ ansible_env.HOME }}/.dotfiles" creates: "{{ ansible_env.HOME }}/.dotfiles/bin/dotfiles"
- name: Create config.yml template: src: config.yml.j2 dest: "{{ ansible_env.HOME }}/.dotfiles/config.yml" when: dotfiles_config is defined
- name: Install modules command: > ./bin/dotfiles install --unattended {{ '--profile ' + dotfiles_profile if dotfiles_profile is defined else '' }} {{ '--skip-failed' if dotfiles_skip_failed | default(false) else '' }} args: chdir: "{{ ansible_env.HOME }}/.dotfiles"GitHub Actions
Section titled “GitHub Actions”name: Test Dotfiles Installation
on: push: branches: [ main ] pull_request: branches: [ main ]
jobs: test-install: runs-on: ubuntu-latest
steps: - name: Checkout repository uses: actions/checkout@v4
- name: Set up Go uses: actions/setup-go@v4 with: go-version: '1.23'
- name: Build dotfiles run: go build -o bin/dotfiles .
- name: Test unattended installation run: | ./bin/dotfiles install --unattended --dry-run ./bin/dotfiles install --unattended --profile minimal --skip-failed
- name: Verify installation run: ./bin/dotfiles status
- name: Test uninstall run: ./bin/dotfiles uninstall git --unattended --dry-runPacker Templates
Section titled “Packer Templates”HCL2 Format:
packer { required_plugins { amazon = { version = ">= 1.0.0" source = "github.com/hashicorp/amazon" } }}
source "amazon-ebs" "dotfiles" { ami_name = "dotfiles-${formatdate("YYYY-MM-DD-hhmm", timestamp())}" instance_type = "t3.micro" region = "us-east-1" source_ami_filter { filters = { name = "ubuntu/images/*ubuntu-jammy-22.04-amd64-server-*" root-device-type = "ebs" virtualization-type = "hvm" } most_recent = true owners = ["099720109477"] } ssh_username = "ubuntu"}
build { sources = ["source.amazon-ebs.dotfiles"]
provisioner "shell" { inline = [ "sudo apt-get update", "sudo apt-get install -y git golang-go", "git clone https://github.com/garygentry/dotfiles.git ~/.dotfiles", "cd ~/.dotfiles && go build -o bin/dotfiles .", "./bin/dotfiles install --unattended --profile server", "./bin/dotfiles status" ] }}Configuration
Section titled “Configuration”Pre-creating config.yml
Section titled “Pre-creating config.yml”Create configuration before installation to control profile and settings:
# Create config filecat > ~/.dotfiles/config.yml <<EOFprofile: minimalsecrets: provider: noop # no secrets backend (this is the default)EOF
# Run installationdotfiles install --unattendedContent Overlay in CI
Section titled “Content Overlay in CI”To materialize identity, secrets choice, and custom profiles/modules inside a container or
CI runner without committing them to the engine repo, point bootstrap.sh at your content
repo. The bootstrap clones it and exports DOTFILES_CONTENT_DIR, which the dotfiles
binary reads to deep-merge your overlay over the repo:
# In a Dockerfile / CI step — public, secret-free overlayRUN curl -sfL https://raw.githubusercontent.com/garygentry/dotfiles/main/bootstrap.sh | \ bash -s -- --unattended --content-repo https://github.com/you/my-dotfiles.gitFor an already-checked-out overlay, set the directory directly before installing:
export DOTFILES_CONTENT_DIR="$PWD/my-dotfiles"dotfiles install --unattended --profile mineKeep CI overlays public and secret-free; for a private overlay use an SSH agent or
--content-auth-cmd. See the Content Overlay guide.
Using Profiles
Section titled “Using Profiles”Create custom profiles for different environments (each profile file has a modules: key):
modules: - git - zsh
# profiles/server.ymlmodules: - git - tmux - zshUse with --profile flag (these names are examples — create the profile first, or use a
built-in like minimal):
dotfiles install --unattended --profile ciEnvironment Variables
Section titled “Environment Variables”The system uses environment variables for configuration:
# Set dotfiles directory (default: ~/.dotfiles)export DOTFILES_DIR=/opt/dotfiles
# Run installationdotfiles install --unattendedHandling Failures
Section titled “Handling Failures”Skip Failed Modules
Section titled “Skip Failed Modules”Continue installation even if some modules fail:
dotfiles install --unattended --skip-failedThis is essential for container images where some modules (e.g., GUI tools) may not be compatible.
Fail Fast
Section titled “Fail Fast”Stop immediately on first failure (useful for testing):
dotfiles install --unattended --fail-fastDry Run
Section titled “Dry Run”Preview what would happen without making changes:
dotfiles install --unattended --dry-runError Handling Example
Section titled “Error Handling Example”#!/bin/bashset -euo pipefail
# Function to handle errorsinstall_dotfiles() { if ! dotfiles install --unattended --skip-failed; then echo "ERROR: Dotfiles installation failed" dotfiles status # Show what succeeded exit 1 fi}
# Run with error handlinginstall_dotfiles
# Verify critical modulesif ! dotfiles status | grep -q "git.*installed"; then echo "ERROR: Critical module 'git' not installed" exit 1fi
echo "Dotfiles installed successfully"Secrets Management
Section titled “Secrets Management”Skipping Secrets
Section titled “Skipping Secrets”In unattended mode, secrets authentication is automatically skipped:
# Secrets authentication is skipped automaticallydotfiles install --unattendedPre-authenticating 1Password
Section titled “Pre-authenticating 1Password”For environments where secrets are needed:
# Authenticate before running dotfilesop account add --address my.1password.com --email user@example.comop signin
# Run installationdotfiles install --unattendedUsing Profiles Without Secrets
Section titled “Using Profiles Without Secrets”Create a profile that excludes secrets-dependent modules:
- git- zsh- tmux# Note: 'ssh' module is excluded (requires 1password)Verification
Section titled “Verification”Exit Codes
Section titled “Exit Codes”The dotfiles CLI uses standard exit codes:
0: Success1: Failure
#!/bin/bashif dotfiles install --unattended; then echo "Installation successful"else echo "Installation failed with exit code $?" exit 1fiStatus Checks
Section titled “Status Checks”Verify installation state:
# Check overall statusdotfiles status
# Check specific moduledotfiles status | grep git
# Programmatic checkif dotfiles status | grep -q "git.*installed"; then echo "Git module is installed"fiLogging
Section titled “Logging”Enable verbose logging for debugging:
# Verbose outputdotfiles install --unattended --verbose
# JSON logging (for log aggregation)dotfiles install --unattended --log-jsonBest Practices
Section titled “Best Practices”1. Use Profiles
Section titled “1. Use Profiles”Create environment-specific profiles:
# Developmentprofiles/dev.yml
# Production serversprofiles/prod.yml
# CI/CDprofiles/ci.yml
# Docker containersprofiles/docker.yml2. Test with Dry Run
Section titled “2. Test with Dry Run”Always test in dry-run mode first:
# Test installationdotfiles install --unattended --profile prod --dry-run
# Review plan, then rundotfiles install --unattended --profile prod3. Use Skip Failed in Containers
Section titled “3. Use Skip Failed in Containers”Container environments may not support all modules:
# DockerfileRUN ./bin/dotfiles install --unattended --skip-failed4. Version Pin Your Dotfiles
Section titled “4. Version Pin Your Dotfiles”Use specific Git tags or commits:
# Terraform user_datagit clone https://github.com/garygentry/dotfiles.gitgit checkout v1.0.05. Capture Logs
Section titled “5. Capture Logs”Save installation logs for debugging:
# Save verbose logsdotfiles install --unattended --verbose > /var/log/dotfiles-install.log 2>&1
# JSON logs for aggregationdotfiles install --unattended --log-json > /var/log/dotfiles.json6. Verify After Installation
Section titled “6. Verify After Installation”Always check status after installation:
#!/bin/bashset -euo pipefail
dotfiles install --unattended --skip-faileddotfiles status
# Verify critical modulesfor module in git zsh; do if ! dotfiles status | grep -q "${module}.*installed"; then echo "ERROR: ${module} not installed" exit 1 fidoneTroubleshooting
Section titled “Troubleshooting”Installation Hangs
Section titled “Installation Hangs”Problem: Installation blocks waiting for input
Solution:
# Ensure --unattended is setdotfiles install --unattended
# Check if stdin is being pipedecho "Installing..." | dotfiles install --unattendedModules Fail in Docker
Section titled “Modules Fail in Docker”Problem: Some modules require interactive terminal or system features
Solution:
# Use --skip-failed to continuedotfiles install --unattended --skip-failed
# Or create a docker-specific profiledotfiles install --unattended --profile dockerSecrets Not Available
Section titled “Secrets Not Available”Problem: 1Password prompts block installation
Solution:
# Unattended mode auto-skips secretsdotfiles install --unattended
# Or disable secrets in configcat > config.yml <<EOFsecrets: provider: noopEOFGo Not Found
Section titled “Go Not Found”Problem: Go binary not in PATH in user data scripts
Solution:
# Add Go to PATHexport PATH="/usr/local/go/bin:$PATH"go build -o bin/dotfiles .Permission Denied
Section titled “Permission Denied”Problem: Running as wrong user
Solution:
# Terraform - run as target useruser_data = <<-EOF #!/bin/bash sudo -u ubuntu bash -c ' cd ~ git clone https://github.com/garygentry/dotfiles.git .dotfiles cd .dotfiles go build -o bin/dotfiles . ./bin/dotfiles install --unattended 'EOFComplete Examples
Section titled “Complete Examples”AWS Auto Scaling Group
Section titled “AWS Auto Scaling Group”resource "aws_launch_template" "dotfiles" { name_prefix = "dotfiles-" image_id = "ami-0c55b159cbfafe1f0" instance_type = "t3.micro"
user_data = base64encode(templatefile("${path.module}/user-data.sh", { dotfiles_repo = "https://github.com/garygentry/dotfiles.git" dotfiles_profile = "server" dotfiles_version = "main" }))
tag_specifications { resource_type = "instance" tags = { Name = "dotfiles-server" } }}
resource "aws_autoscaling_group" "dotfiles" { desired_capacity = 2 max_size = 4 min_size = 1
launch_template { id = aws_launch_template.dotfiles.id version = "$Latest" }
vpc_zone_identifier = var.subnet_ids}user-data.sh:
#!/bin/bashset -euo pipefail
# Install dependenciesapt-get updateapt-get install -y git golang-go curl
# Clone and install as ubuntu usersudo -u ubuntu bash <<'SCRIPT'cd ~git clone ${dotfiles_repo} .dotfilescd .dotfilesgit checkout ${dotfiles_version}go build -o bin/dotfiles ../bin/dotfiles install --unattended --profile ${dotfiles_profile} --skip-failed
# Verify./bin/dotfiles statusSCRIPT
echo "Dotfiles installation complete"GitLab CI
Section titled “GitLab CI”stages: - test - build
test-dotfiles: stage: test image: ubuntu:22.04 before_script: - apt-get update && apt-get install -y git golang-go script: - go build -o bin/dotfiles . - ./bin/dotfiles install --unattended --dry-run - ./bin/dotfiles install --unattended --profile ci --skip-failed - ./bin/dotfiles status artifacts: when: on_failure paths: - .state/ expire_in: 1 week
build-image: stage: build image: docker:latest services: - docker:dind script: - docker build -t myapp/dotfiles:latest . - docker run myapp/dotfiles:latest dotfiles statusSummary
Section titled “Summary”The --unattended flag makes the dotfiles system fully compatible with automated workflows:
- ✅ Zero interactive prompts
- ✅ Automatic fallback to defaults
- ✅ Works in CI/CD, IaC, and containers
- ✅ Compatible with all major cloud providers
- ✅ Comprehensive error handling
- ✅ Flexible profile system
For questions or issues, see the main README or Troubleshooting Guide.