CI/CD Patterns
Three GitHub Actions workflows in .github/workflows/:
| Workflow | Trigger | Purpose |
|---|---|---|
ci.yml |
Push/PR to main | Build, lint, test, integration checks |
release.yml |
Push to main (cli/conf paths) | Build release binaries, create GitHub Release |
docker.yml |
Push to main | Build and push Docker image to Docker Hub |
CI Pipeline (ci.yml)
Job Structure
rust-fmt ─────────────────────────────────────────────┐
lint (ShellCheck, PSScriptAnalyzer) ──────────────────┤
validate-config ──────────────────────────────────────┤
audit (cargo-audit) ──────────────────────────────────┤
build-linux ──┬── integration-linux (base, desktop) ──┤
├── test-install-uninstall ──────────────┤
├── test-applications (git, zsh, vim…) ──┤
├── test-git-hooks ──────────────────────┤
└── test-shell-wrapper-linux ────────────┤
build-windows ┬── integration-windows (base, desktop) ┤
├── test-install-uninstall-windows ──────┤
└── test-shell-wrapper-windows ──────────┤
ci-success (gate) ────────────────────────────────────┘
Key patterns:
concurrency: ci-${{ github.ref }}withcancel-in-progress: truepermissions: contents: read(least privilege)- Uses
--profile cifor faster builds (optimised dev profile) - Build artifacts uploaded with 1-day retention for downstream jobs
ci-successgate job usesif: always()with failure/cancelled check
Build Profiles
CI uses cargo build --profile ci (not --release) for faster compilation
while still catching release-mode issues. The release workflow uses
cargo build --release.
Test Scripts
Integration test logic lives in .github/workflows/scripts/:
scripts/
├── linux/
│ ├── lib/test-helpers.sh # Shared test helpers
│ ├── test-applications.sh # App-specific tests (git, zsh, vim, nvim)
│ ├── test-config.sh # Config validation checks
│ ├── test-git-hooks.sh # Pre-commit hook tests
│ ├── test-shell-wrapper.sh # dotfiles.sh wrapper tests
│ ├── test-static-analysis.sh # ShellCheck/PSScriptAnalyzer runners
│ └── test-uninstall.sh # Install/uninstall round-trip
└── windows/
├── Test-ShellWrapper.ps1 # dotfiles.ps1 wrapper tests
└── Test-InstallUninstall.ps1
Integration Test Strategy
- Dry-run profile tests: Run
bin/dotfiles --root . -p <profile> -d installfor each profile on both Linux and Windows - Config validation: Run
bin/dotfiles --root . -p <profile> test - Install/uninstall round-trip: Install then uninstall, verify cleanup
- Application tests: Install with base profile, then test each app (git config, zsh completion, vim/nvim open and plugins)
Release Pipeline (release.yml)
- Builds release binaries on both Linux and Windows
- Sets
DOTFILES_VERSION=v0.1.${{ github.run_number }}as env var build.rsembeds this version viacargo:rustc-env=DOTFILES_VERSION- Strips the Linux binary (
strip cli/target/release/dotfiles) - Renames to
dotfiles-linux-x86_64/dotfiles-windows-x86_64.exe - Generates
checksums.sha256viasha256sum - Creates a GitHub Release with
softprops/action-gh-release@v2
The shell wrappers (dotfiles.sh, dotfiles.ps1) download these release
binaries, verify the SHA256 checksum, and cache the installed version.
Adding a New CI Job
- Add the job to
ci.ymlwith appropriateneeds:dependencies - Add the job name to the
ci-successgate'sneeds:list - Use
fail-fast: falsein matrix strategies for independent test cases - Use the shared test helper library in
scripts/linux/lib/test-helpers.sh - Download build artifacts when tests need the compiled binary
Rules
- All CI jobs must be listed in the
ci-successgate'sneeds:array - Use
--profile ciin CI builds,--releaseonly in release workflow - Test scripts go in
.github/workflows/scripts/— not inline in YAML - Integration tests use
--root .to run against the checked-out repo - Release version comes from
github.run_number— no manual tagging - Binary checksums are always generated and published with releases
Source: sneivandt/dotfiles — distributed by TomeVault.