GitHub Release Installer Library¶
Overview¶
The GitHub Release Installer library provides focused helper functions for installing binary tools from GitHub releases. It eliminates code duplication across the installer scripts in management/common/install/github-releases/ while maintaining clarity and simplicity.
Design Philosophy¶
The library follows the "medium abstraction" principle:
- Focused helpers - Only abstract truly repetitive patterns
- Inline complexity - Single-use operations stay inline in functions
- Explicit configuration - Each script contains its own configuration inline
- No YAML complexity - Avoid complex packages.yml parsing for variations
- Straightforward - Easy to trace and understand what's happening
Architecture¶
Library Chain¶
installer-script.sh
└─> error-handling.sh (set -euo pipefail, traps, cleanup)
└─> logging.sh (status messages with [LEVEL] prefixes)
└─> colors.sh
Each installer script sources error-handling.sh, which automatically provides:
- Error safety with
set -euo pipefail - Trap handlers for cleanup
- Structured logging (auto-detects terminal vs pipe)
- Consistent error messages with file:line references
Library Functions¶
Located in management/common/lib/github-release-installer.sh:
1. get_platform_arch()¶
Handles platform/architecture detection with customizable capitalization.
Usage:
Why it exists: Different GitHub projects use different naming conventions:
lazygit:Darwin_x86_64duf:darwin_x86_64(lowercase)zk:macos-x86_64(different platform name)
2. get_latest_version()¶
Fetches the latest release version from GitHub API.
Usage:
Why it exists: Every installer needs to fetch versions, same pattern every time.
3. should_skip_install()¶
Checks if installation should be skipped (already installed, unless FORCE_INSTALL=true).
Usage:
Why it exists: Idempotency check used by every installer.
4. install_from_tarball()¶
Complete installation pattern for tar.gz archives.
What it does:
- Downloads tarball to /tmp
- Registers cleanup trap
- Extracts archive
- Moves binary to ~/.local/bin
- Sets executable permissions
- Verifies installation
Usage:
Why it's one function: Download, extract, install, verify are always done together. Splitting them into separate functions creates unnecessary indirection.
5. install_from_zip()¶
Same as install_from_tarball() but for zip files.
Usage:
Script Patterns¶
Simple Tarball Installer¶
Most common pattern (majority of tools):
#!/usr/bin/env bash
set -euo pipefail
DOTFILES_DIR="${DOTFILES_DIR:-$HOME/dotfiles}"
source "$DOTFILES_DIR/management/common/lib/error-handling.sh"
enable_error_traps
source "$DOTFILES_DIR/management/common/lib/github-release-installer.sh"
BINARY_NAME="lazygit"
REPO="jesseduffield/lazygit"
TARGET_BIN="$HOME/.local/bin/$BINARY_NAME"
print_banner "Installing LazyGit"
if should_skip_install "$TARGET_BIN" "$BINARY_NAME"; then
exit_success
fi
VERSION=$(get_latest_version "$REPO")
log_info "Latest version: $VERSION"
PLATFORM_ARCH=$(get_platform_arch "Darwin_x86_64" "Darwin_arm64" "Linux_x86_64")
DOWNLOAD_URL="https://github.com/${REPO}/releases/download/${VERSION}/lazygit_${VERSION#v}_${PLATFORM_ARCH}.tar.gz"
install_from_tarball "$BINARY_NAME" "$DOWNLOAD_URL" "lazygit"
print_banner_success "LazyGit installation complete"
exit_success
Lines: ~40-50 (was 90-120)
Custom Installer (Special Cases)¶
Some tools need custom handling:
- yazi: Installs multiple binaries (yazi + ya), adds plugins
- tenv: Installs 7 binaries (tenv + proxy binaries)
- terraformer: Downloads raw binary (no archive)
- zk: Complex platform detection (macos vs linux, different arch naming)
These scripts use library helpers where applicable but handle their unique requirements inline.
Code Savings¶
The library reduced per-script boilerplate by roughly half compared to the pre-library era, where each script duplicated platform detection, version fetching, download, and installation logic. The previous iteration (401 lines, 16 functions) was over-abstracted; the current library has 5 focused functions.
See management/common/install/github-releases/ for all current scripts.
Custom Installers (Not Using Library)¶
Some tools have unique requirements that don't fit the GitHub release pattern. These live in management/common/install/custom-installers/ instead. All still use error-handling.sh for structured logging consistency.
Design Decisions¶
Why Not More Abstraction?¶
Rejected: Complex packages.yml with all download patterns
# TOO COMPLEX - requires YAML parser, hard to trace
github_binaries:
- name: lazygit
archive_format: tar.gz
url_pattern: "{repo}/releases/download/{version}/lazygit_{version}_{platform}_{arch}.tar.gz"
binary_pattern: "lazygit"
Chosen: Inline configuration in each script
# SIMPLE - easy to trace, self-contained
DOWNLOAD_URL="https://github.com/${REPO}/releases/download/${VERSION}/lazygit_${VERSION#v}_${PLATFORM_ARCH}.tar.gz"
Rationale: URL patterns vary enough that YAML templates become complex. Inline keeps it explicit and traceable.
Why Not Version Checking?¶
Rejected: Minimum version requirements, complex version comparison
Chosen: Always install latest from GitHub API
Rationale:
- Simpler code
- Latest is usually what you want
- Can pin specific version by editing script if needed
- Reduces maintenance burden
Why Inline Download/Extract/Install?¶
Rejected: Separate download_release(), extract_tarball(), install_binary() functions
Chosen: Single install_from_tarball() function with inline operations
Rationale:
- These operations are ALWAYS done together
- Separate functions create unnecessary indirection
- Harder to trace: installer → install_from_tarball → download_release → download_with_retry
- Inline is more straightforward
Integration with Error Handling¶
The library assumes error-handling.sh has been sourced by the calling script. This provides:
Automatic Cleanup¶
Cleanup happens automatically on exit (success or failure).
Error Context¶
Errors include file:line references for debugging.
Structured Logging¶
Auto-detects terminal vs pipe:
Terminal mode:
Structured mode (pipe/log):
Adding a New Tool¶
Steps¶
- Create new script in
management/common/install/github-releases/ - Use template pattern (see Simple Tarball Installer above)
- Configure: BINARY_NAME, REPO, download URL pattern
- Handle special cases inline if needed
- Test on all platforms
Time Required¶
- Before library: 30-60 minutes (80-120 lines of boilerplate)
- After library: 5-10 minutes (40-50 lines, mostly copy-paste)
6x faster
Testing¶
Run individual installer:
Force reinstall:
Test structured logging:
# Visual mode (terminal)
bash management/common/install/github-releases/lazygit.sh
# Structured mode (pipe)
bash management/common/install/github-releases/lazygit.sh 2>&1 | cat
Future Improvements¶
Possible (Low Priority)¶
- Optional checksum verification (verify if present, but not required)
- Lightweight install log for audit trail (append-only)
- Helper for multi-binary installation pattern
Not Recommended¶
- ❌ Complex packages.yml parsing - contradicts straightforward principle
- ❌ Automatic version checking/upgrades - adds complexity
- ❌ Rollback capability - idempotency is sufficient
- ❌ More abstraction layers - keep it simple
Related Documentation¶
- Error Handling
- Shell Libraries
- Production-Grade Management Enhancements (planning doc)
Files¶
Library:
management/common/lib/github-release-installer.sh
Converted Scripts: See management/common/install/github-releases/ for the full current listing.
Moved to Custom Installers:
management/common/install/custom-installers/awscli.sh- Uses AWS custom installermanagement/common/install/custom-installers/claude-code.sh- Uses official installer scriptmanagement/common/install/custom-installers/terraform-ls.sh- Uses releases.hashicorp.com (not GitHub)
Moved back to GitHub Releases:
management/common/install/github-releases/tenv.sh- Terraform is a program, not a language. Grouped by installation method (GitHub releases)