From 5354528446c9874c063a471aa079a7f0917d5d36 Mon Sep 17 00:00:00 2001 From: Jason Garber Date: Fri, 1 Mar 2024 20:27:26 +0000 Subject: [PATCH] Refactor shellcheck feature --- src/shellcheck/devcontainer-feature.json | 2 +- src/shellcheck/install.sh | 60 ++++++----- src/shellcheck/shared.lib.sh | 100 ++++++++++++++++++ .../install-bookworm-with-options.sh | 14 +++ test/shellcheck/install-bookworm.sh | 14 +++ test/shellcheck/install-jammy-with-options.sh | 14 +++ test/shellcheck/install-jammy.sh | 14 +++ test/shellcheck/scenarios.json | 28 ++++- test/shellcheck/shellcheck-version.sh | 18 ---- test/shellcheck/test.sh | 34 ------ 10 files changed, 212 insertions(+), 86 deletions(-) create mode 100755 src/shellcheck/shared.lib.sh create mode 100755 test/shellcheck/install-bookworm-with-options.sh create mode 100755 test/shellcheck/install-bookworm.sh create mode 100755 test/shellcheck/install-jammy-with-options.sh create mode 100755 test/shellcheck/install-jammy.sh delete mode 100755 test/shellcheck/shellcheck-version.sh diff --git a/src/shellcheck/devcontainer-feature.json b/src/shellcheck/devcontainer-feature.json index 204cc50..76d10ca 100644 --- a/src/shellcheck/devcontainer-feature.json +++ b/src/shellcheck/devcontainer-feature.json @@ -1,7 +1,7 @@ { "name": "ShellCheck", "id": "shellcheck", - "version": "1.0.0", + "version": "1.1.0", "description": "Install ShellCheck, a static analysis tool for shell scripts.", "options": { "version": { diff --git a/src/shellcheck/install.sh b/src/shellcheck/install.sh index 93ebe4e..1e166b5 100755 --- a/src/shellcheck/install.sh +++ b/src/shellcheck/install.sh @@ -1,53 +1,57 @@ -#!/usr/bin/env sh +#!/usr/bin/env bash set -e SHELLCHECK_VERSION="${VERSION:-"os-provided"}" -INSTALL_PATH="${INSTALLPATH:-"/usr/local/bin"}" - -if [ "$(id -u)" -ne 0 ]; then - printf 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.' - exit 1 -fi +SHELLCHECK_INSTALL_PATH="${INSTALLPATH:-"/usr/local/bin"}" +SHELLCHECK_REPOSITORY="https://github.com/koalaman/shellcheck" +DIRNAME=$(dirname -- "${0}") +SCRIPT_DIR=$(cd -- "${DIRNAME}" > /dev/null 2>&1 && pwd) -if [ "${SHELLCHECK_VERSION}" = "os-provided" ]; then - apt update --yes - apt install --no-install-recommends --yes shellcheck +# shellcheck source=./src/shellcheck/shared.lib.sh +. "${SCRIPT_DIR}"/shared.lib.sh +if type shellcheck > /dev/null 2>&1; then + echo "Detected existing system install: $(shellcheck --version)" + clean_up exit 0 fi -curl_installed="" - -if ! type curl >/dev/null 2>&1; then - apt update --yes - apt install --no-install-recommends --yes curl ca-certificates xz-utils +check_packages curl ca-certificates xz-utils - curl_installed="true" +if [[ "${SHELLCHECK_VERSION}" = "os-provided" ]]; then + check_packages shellcheck + exit 0 fi -if [ "${SHELLCHECK_VERSION}" = "latest" ]; then - SHELLCHECK_VERSION="$(curl -s --head https://github.com/koalaman/shellcheck/releases/latest | sed -nr 's/location:.*\/v(.+)/\1/ip' | tr -d '\r')" +if [[ "${SHELLCHECK_VERSION}" = "latest" ]]; then + SHELLCHECK_VERSION=$(set -e; latest_release_version "${SHELLCHECK_REPOSITORY}") fi machine="$(uname -m)" case "${machine}" in - aarch64) arch="aarch64" ;; - arm*) arch="armv6" ;; - x86_64) arch="x86_64" ;; + aarch64) + arch="aarch64" + ;; + arm*) + arch="armv6" + ;; + x86_64) + arch="x86_64" + ;; *) echo "Could not determine arch from machine hardware name '${machine}'" >&2 exit 1 - ;; + ;; esac # https://github.com/koalaman/shellcheck/releases/download/v0.9.0/shellcheck-v0.9.0.linux.aarch64.tar.xz -file="shellcheck-v${SHELLCHECK_VERSION}.linux.${arch}.tar.xz" -url="https://github.com/koalaman/shellcheck/releases/download/v${SHELLCHECK_VERSION}/${file}" +url="${SHELLCHECK_REPOSITORY}/releases/download/v${SHELLCHECK_VERSION}/shellcheck-v${SHELLCHECK_VERSION}.linux.${arch}.tar.xz" -curl -sSL "${url}" | tar --strip-components=1 -Jxvf - -C "${INSTALL_PATH}" "shellcheck-v${SHELLCHECK_VERSION}/shellcheck" +echo "Downloading ${url} with curl..." -if [ -n "${curl_installed}" ]; then - apt purge curl xz-utils --autoremove --yes -fi +# curl -L "${url}" | tar xvf -C "${SHELLCHECK_INSTALL_PATH}" shellcheck +curl -L "${url}" | tar --strip-components=1 -Jxvf - -C "${SHELLCHECK_INSTALL_PATH}" "shellcheck-v${SHELLCHECK_VERSION}/shellcheck" + +echo "Done!" diff --git a/src/shellcheck/shared.lib.sh b/src/shellcheck/shared.lib.sh new file mode 100755 index 0000000..178e005 --- /dev/null +++ b/src/shellcheck/shared.lib.sh @@ -0,0 +1,100 @@ +#!/usr/bin/env bash + +if [[ "$(id -u)" -ne 0 ]]; then + printf 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.' + exit 1 +fi + +# Bring in ID, ID_LIKE, VERSION_ID, VERSION_CODENAME +. /etc/os-release +# Get an adjusted ID independent of distro variants +# shellcheck disable=SC2154 +if [[ "${ID}" = "debian" ]] || [[ "${ID_LIKE}" = "debian" ]]; then + ADJUSTED_ID="debian" +elif [[ "${ID}" = "rhel" || "${ID}" = "fedora" || "${ID}" = "mariner" || "${ID_LIKE}" = *"rhel"* || "${ID_LIKE}" = *"fedora"* || "${ID_LIKE}" = *"mariner"* ]]; then + ADJUSTED_ID="rhel" + # shellcheck disable=SC2034 + VERSION_CODENAME="${ID}${VERSION_ID}" +else + echo "Linux distro ${ID} not supported." + exit 1 +fi + +if type apt-get > /dev/null 2>&1; then + INSTALL_CMD="apt-get" +elif type microdnf > /dev/null 2>&1; then + INSTALL_CMD="microdnf" +elif type dnf > /dev/null 2>&1; then + INSTALL_CMD="dnf" +elif type yum > /dev/null 2>&1; then + INSTALL_CMD="yum" +else + echo "Unable to find a supported package manager." + exit 1 +fi + +clean_up() { + case ${ADJUSTED_ID} in + debian) + rm -rf /var/lib/apt/lists/* + ;; + rhel) + rm -rf /var/cache/dnf/* + rm -rf /var/cache/yum/* + ;; + *) + ;; + esac +} + +pkg_mgr_update() { + if [[ "${INSTALL_CMD}" = "apt-get" ]]; then + if [[ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]]; then + echo "Running apt-get update..." + ${INSTALL_CMD} update -y + fi + elif [[ ${INSTALL_CMD} = "dnf" ]] || [[ ${INSTALL_CMD} = "yum" ]]; then + if [[ "$(find /var/cache/"${INSTALL_CMD}"/* | wc -l)" = "0" ]]; then + echo "Running ${INSTALL_CMD} check-update..." + ${INSTALL_CMD} check-update + fi + fi +} + +check_packages() { + if [[ "${INSTALL_CMD}" = "apt-get" ]]; then + if ! dpkg -s "$@" > /dev/null 2>&1; then + pkg_mgr_update + ${INSTALL_CMD} -y install --no-install-recommends "$@" + fi + elif [[ "${INSTALL_CMD}" = "dnf" ]] || [[ "${INSTALL_CMD}" = "yum" ]]; then + _num_pkgs=$(echo "$@" | tr ' ' \\012 | wc -l) + _num_installed=$(${INSTALL_CMD} -C list installed "$@" | sed '1,/^Installed/d' | wc -l) + if [[ "${_num_pkgs}" != "${_num_installed}" ]]; then + pkg_mgr_update + ${INSTALL_CMD} -y install "$@" + fi + elif [[ "${INSTALL_CMD}" = "microdnf" ]]; then + ${INSTALL_CMD} -y install \ + --refresh \ + --best \ + --nodocs \ + --noplugins \ + --setopt=install_weak_deps=0 \ + "$@" + else + echo "Linux distro ${ID} not supported." + exit 1 + fi +} + +latest_release_version() { + if [[ $# -eq 0 ]]; then + echo "No repository URL provided." + exit 1 + fi + + curl -s --head "${1}"/releases/latest | sed -nr 's/location:.*\/v(.+)/\1/ip' | tr -d '\r' +} + +export DEBIAN_FRONTEND="noninteractive" diff --git a/test/shellcheck/install-bookworm-with-options.sh b/test/shellcheck/install-bookworm-with-options.sh new file mode 100755 index 0000000..e32320d --- /dev/null +++ b/test/shellcheck/install-bookworm-with-options.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +set -e + +# Optional: Import test library bundled with the devcontainer CLI +# shellcheck source=/dev/null +source dev-container-features-test-lib + +# Feature-specific tests +check "version" bash -c "shellcheck --version | grep 0.8.0" +check "which shellcheck" bash -c "which shellcheck | grep /usr/bin/shellcheck" + +# Report result +reportResults diff --git a/test/shellcheck/install-bookworm.sh b/test/shellcheck/install-bookworm.sh new file mode 100755 index 0000000..34e920e --- /dev/null +++ b/test/shellcheck/install-bookworm.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +set -e + +# Optional: Import test library bundled with the devcontainer CLI +# shellcheck source=/dev/null +source dev-container-features-test-lib + +# Feature-specific tests +check "version" shellcheck --version +check "which shellcheck" bash -c "which shellcheck | grep /usr/bin/shellcheck" + +# Report result +reportResults diff --git a/test/shellcheck/install-jammy-with-options.sh b/test/shellcheck/install-jammy-with-options.sh new file mode 100755 index 0000000..e32320d --- /dev/null +++ b/test/shellcheck/install-jammy-with-options.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +set -e + +# Optional: Import test library bundled with the devcontainer CLI +# shellcheck source=/dev/null +source dev-container-features-test-lib + +# Feature-specific tests +check "version" bash -c "shellcheck --version | grep 0.8.0" +check "which shellcheck" bash -c "which shellcheck | grep /usr/bin/shellcheck" + +# Report result +reportResults diff --git a/test/shellcheck/install-jammy.sh b/test/shellcheck/install-jammy.sh new file mode 100755 index 0000000..2dd682e --- /dev/null +++ b/test/shellcheck/install-jammy.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +set -e + +# Optional: Import test library bundled with the devcontainer CLI +# shellcheck source=/dev/null +source dev-container-features-test-lib + +# Feature-specific tests +check "version" shellcheck --version +check "which shellcheck" bash -c "which shellcheck | grep /usr/local/bin/shellcheck" + +# Report result +reportResults diff --git a/test/shellcheck/scenarios.json b/test/shellcheck/scenarios.json index e64f3c9..67ed133 100644 --- a/test/shellcheck/scenarios.json +++ b/test/shellcheck/scenarios.json @@ -1,17 +1,35 @@ { - "shellcheck-version": { - "image": "debian:latest", + "install-bookworm": { + "image": "debian:bookworm", + "features": { + "shellcheck": {} + } + }, + + "install-bookworm-with-options": { + "image": "debian:bookworm", + "features": { + "shellcheck": { + "version": "0.8.0", + "installPath": "/usr/bin" + } + } + }, + + "install-jammy": { + "image": "ubuntu:jammy", "features": { "shellcheck": { - "version": "0.8.0" + "version": "latest" } } }, - "shellcheck-install-path": { - "image": "debian:latest", + "install-jammy-with-options": { + "image": "ubuntu:jammy", "features": { "shellcheck": { + "version": "0.8.0", "installPath": "/usr/bin" } } diff --git a/test/shellcheck/shellcheck-version.sh b/test/shellcheck/shellcheck-version.sh deleted file mode 100755 index 59a26c3..0000000 --- a/test/shellcheck/shellcheck-version.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env bash - -set -e - -# Optional: Import test library bundled with the devcontainer CLI -# See https://github.com/devcontainers/cli/blob/HEAD/docs/features/test.md#dev-container-features-test-lib -# Provides the 'check' and 'reportResults' commands. -# shellcheck source=/dev/null -source dev-container-features-test-lib - -# Feature-specific tests -# The 'check' command comes from the dev-container-features-test-lib. Syntax is... -# check