Files
computer-playbook/utils/install/lint/hadolint.py
kevinveenbirkenbachandClaude Opus 5 8b7424e5fa fix(lint): pin the GitHub-release lint tools in roles/sys-lint
make install-lint resolved each tool's latest tag at install time, so a DNS
hiccup failed the target outright and two runs of the same commit could
install different linter versions.

roles/sys-lint/meta/services.yml now records the repository and ref of
actionlint, hadolint and shfmt. The pairs use the shape
utils/update/repository.py already scans, so update-repository-refs bumps
them by pull request. utils/install/lint/pinned.py reads the pin and applies
the <TOOL>_VERSION override; the three installers lost their duplicated
resolver along with resolve_latest_tag.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-08 19:33:22 +02:00

70 lines
2.0 KiB
Python

"""Install hadolint via GitHub-release prebuilt binary."""
from __future__ import annotations
import os
import platform
import tempfile
from pathlib import Path
from utils.install.github_release import download_release_asset
from utils.install.lint.pinned import resolve_release
from utils.install.primitives import (
ensure_dir_on_path,
install_with_optional_sudo,
log,
which,
)
_DEFAULT_INSTALL_DIR = os.environ.get("HADOLINT_INSTALL_DIR", "/usr/local/bin")
def _detect_os() -> str:
system = platform.system()
if system == "Linux":
return "Linux"
if system == "Darwin":
return "Darwin"
raise RuntimeError(f"Unsupported OS for hadolint prebuilt binary: {system}")
def _detect_arch() -> str:
machine = platform.machine().lower()
if machine in ("x86_64", "amd64"):
return "x86_64"
if machine in ("aarch64", "arm64"):
return "arm64"
raise RuntimeError(
f"Unsupported architecture for hadolint prebuilt binary: {machine}"
)
def _install_binary() -> None:
slug, version = resolve_release("hadolint")
asset_name = f"hadolint-{_detect_os()}-{_detect_arch()}"
url = f"https://github.com/{slug}/releases/download/v{version}/{asset_name}"
log(f"Installing hadolint v{version} from GitHub releases")
with tempfile.TemporaryDirectory() as tmpdir:
binary_src = Path(tmpdir) / "hadolint"
download_release_asset(url, str(binary_src))
install_with_optional_sudo(["install", "-d", _DEFAULT_INSTALL_DIR])
dst = str(Path(_DEFAULT_INSTALL_DIR) / "hadolint")
install_with_optional_sudo(["install", "-m", "0755", str(binary_src), dst])
def ensure() -> None:
if which("hadolint"):
return
log("Missing command 'hadolint'. Installing official prebuilt binary.")
_install_binary()
ensure_dir_on_path(_DEFAULT_INSTALL_DIR)
if not which("hadolint"):
raise RuntimeError(
"Command 'hadolint' is still unavailable after installation."
)