Skip to content

Commit 7c022aa

Browse files
Refactor shellcheck feature (#5)
2 parents 3ca31c4 + 5354528 commit 7c022aa

10 files changed

+212
-86
lines changed

src/shellcheck/devcontainer-feature.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "ShellCheck",
33
"id": "shellcheck",
4-
"version": "1.0.0",
4+
"version": "1.1.0",
55
"description": "Install ShellCheck, a static analysis tool for shell scripts.",
66
"options": {
77
"version": {

src/shellcheck/install.sh

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,57 @@
1-
#!/usr/bin/env sh
1+
#!/usr/bin/env bash
22

33
set -e
44

55
SHELLCHECK_VERSION="${VERSION:-"os-provided"}"
6-
INSTALL_PATH="${INSTALLPATH:-"/usr/local/bin"}"
7-
8-
if [ "$(id -u)" -ne 0 ]; then
9-
printf 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
10-
exit 1
11-
fi
6+
SHELLCHECK_INSTALL_PATH="${INSTALLPATH:-"/usr/local/bin"}"
7+
SHELLCHECK_REPOSITORY="https://github.com/koalaman/shellcheck"
128

9+
DIRNAME=$(dirname -- "${0}")
10+
SCRIPT_DIR=$(cd -- "${DIRNAME}" > /dev/null 2>&1 && pwd)
1311

14-
if [ "${SHELLCHECK_VERSION}" = "os-provided" ]; then
15-
apt update --yes
16-
apt install --no-install-recommends --yes shellcheck
12+
# shellcheck source=./src/shellcheck/shared.lib.sh
13+
. "${SCRIPT_DIR}"/shared.lib.sh
1714

15+
if type shellcheck > /dev/null 2>&1; then
16+
echo "Detected existing system install: $(shellcheck --version)"
17+
clean_up
1818
exit 0
1919
fi
2020

21-
curl_installed=""
22-
23-
if ! type curl >/dev/null 2>&1; then
24-
apt update --yes
25-
apt install --no-install-recommends --yes curl ca-certificates xz-utils
21+
check_packages curl ca-certificates xz-utils
2622

27-
curl_installed="true"
23+
if [[ "${SHELLCHECK_VERSION}" = "os-provided" ]]; then
24+
check_packages shellcheck
25+
exit 0
2826
fi
2927

30-
if [ "${SHELLCHECK_VERSION}" = "latest" ]; then
31-
SHELLCHECK_VERSION="$(curl -s --head https://github.com/koalaman/shellcheck/releases/latest | sed -nr 's/location:.*\/v(.+)/\1/ip' | tr -d '\r')"
28+
if [[ "${SHELLCHECK_VERSION}" = "latest" ]]; then
29+
SHELLCHECK_VERSION=$(set -e; latest_release_version "${SHELLCHECK_REPOSITORY}")
3230
fi
3331

3432
machine="$(uname -m)"
3533
case "${machine}" in
36-
aarch64) arch="aarch64" ;;
37-
arm*) arch="armv6" ;;
38-
x86_64) arch="x86_64" ;;
34+
aarch64)
35+
arch="aarch64"
36+
;;
37+
arm*)
38+
arch="armv6"
39+
;;
40+
x86_64)
41+
arch="x86_64"
42+
;;
3943
*)
4044
echo "Could not determine arch from machine hardware name '${machine}'" >&2
4145
exit 1
42-
;;
46+
;;
4347
esac
4448

4549
# https://github.com/koalaman/shellcheck/releases/download/v0.9.0/shellcheck-v0.9.0.linux.aarch64.tar.xz
46-
file="shellcheck-v${SHELLCHECK_VERSION}.linux.${arch}.tar.xz"
47-
url="https://github.com/koalaman/shellcheck/releases/download/v${SHELLCHECK_VERSION}/${file}"
50+
url="${SHELLCHECK_REPOSITORY}/releases/download/v${SHELLCHECK_VERSION}/shellcheck-v${SHELLCHECK_VERSION}.linux.${arch}.tar.xz"
4851

49-
curl -sSL "${url}" | tar --strip-components=1 -Jxvf - -C "${INSTALL_PATH}" "shellcheck-v${SHELLCHECK_VERSION}/shellcheck"
52+
echo "Downloading ${url} with curl..."
5053

51-
if [ -n "${curl_installed}" ]; then
52-
apt purge curl xz-utils --autoremove --yes
53-
fi
54+
# curl -L "${url}" | tar xvf -C "${SHELLCHECK_INSTALL_PATH}" shellcheck
55+
curl -L "${url}" | tar --strip-components=1 -Jxvf - -C "${SHELLCHECK_INSTALL_PATH}" "shellcheck-v${SHELLCHECK_VERSION}/shellcheck"
56+
57+
echo "Done!"

src/shellcheck/shared.lib.sh

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
#!/usr/bin/env bash
2+
3+
if [[ "$(id -u)" -ne 0 ]]; then
4+
printf 'Script must be run as root. Use sudo, su, or add "USER root" to your Dockerfile before running this script.'
5+
exit 1
6+
fi
7+
8+
# Bring in ID, ID_LIKE, VERSION_ID, VERSION_CODENAME
9+
. /etc/os-release
10+
# Get an adjusted ID independent of distro variants
11+
# shellcheck disable=SC2154
12+
if [[ "${ID}" = "debian" ]] || [[ "${ID_LIKE}" = "debian" ]]; then
13+
ADJUSTED_ID="debian"
14+
elif [[ "${ID}" = "rhel" || "${ID}" = "fedora" || "${ID}" = "mariner" || "${ID_LIKE}" = *"rhel"* || "${ID_LIKE}" = *"fedora"* || "${ID_LIKE}" = *"mariner"* ]]; then
15+
ADJUSTED_ID="rhel"
16+
# shellcheck disable=SC2034
17+
VERSION_CODENAME="${ID}${VERSION_ID}"
18+
else
19+
echo "Linux distro ${ID} not supported."
20+
exit 1
21+
fi
22+
23+
if type apt-get > /dev/null 2>&1; then
24+
INSTALL_CMD="apt-get"
25+
elif type microdnf > /dev/null 2>&1; then
26+
INSTALL_CMD="microdnf"
27+
elif type dnf > /dev/null 2>&1; then
28+
INSTALL_CMD="dnf"
29+
elif type yum > /dev/null 2>&1; then
30+
INSTALL_CMD="yum"
31+
else
32+
echo "Unable to find a supported package manager."
33+
exit 1
34+
fi
35+
36+
clean_up() {
37+
case ${ADJUSTED_ID} in
38+
debian)
39+
rm -rf /var/lib/apt/lists/*
40+
;;
41+
rhel)
42+
rm -rf /var/cache/dnf/*
43+
rm -rf /var/cache/yum/*
44+
;;
45+
*)
46+
;;
47+
esac
48+
}
49+
50+
pkg_mgr_update() {
51+
if [[ "${INSTALL_CMD}" = "apt-get" ]]; then
52+
if [[ "$(find /var/lib/apt/lists/* | wc -l)" = "0" ]]; then
53+
echo "Running apt-get update..."
54+
${INSTALL_CMD} update -y
55+
fi
56+
elif [[ ${INSTALL_CMD} = "dnf" ]] || [[ ${INSTALL_CMD} = "yum" ]]; then
57+
if [[ "$(find /var/cache/"${INSTALL_CMD}"/* | wc -l)" = "0" ]]; then
58+
echo "Running ${INSTALL_CMD} check-update..."
59+
${INSTALL_CMD} check-update
60+
fi
61+
fi
62+
}
63+
64+
check_packages() {
65+
if [[ "${INSTALL_CMD}" = "apt-get" ]]; then
66+
if ! dpkg -s "$@" > /dev/null 2>&1; then
67+
pkg_mgr_update
68+
${INSTALL_CMD} -y install --no-install-recommends "$@"
69+
fi
70+
elif [[ "${INSTALL_CMD}" = "dnf" ]] || [[ "${INSTALL_CMD}" = "yum" ]]; then
71+
_num_pkgs=$(echo "$@" | tr ' ' \\012 | wc -l)
72+
_num_installed=$(${INSTALL_CMD} -C list installed "$@" | sed '1,/^Installed/d' | wc -l)
73+
if [[ "${_num_pkgs}" != "${_num_installed}" ]]; then
74+
pkg_mgr_update
75+
${INSTALL_CMD} -y install "$@"
76+
fi
77+
elif [[ "${INSTALL_CMD}" = "microdnf" ]]; then
78+
${INSTALL_CMD} -y install \
79+
--refresh \
80+
--best \
81+
--nodocs \
82+
--noplugins \
83+
--setopt=install_weak_deps=0 \
84+
"$@"
85+
else
86+
echo "Linux distro ${ID} not supported."
87+
exit 1
88+
fi
89+
}
90+
91+
latest_release_version() {
92+
if [[ $# -eq 0 ]]; then
93+
echo "No repository URL provided."
94+
exit 1
95+
fi
96+
97+
curl -s --head "${1}"/releases/latest | sed -nr 's/location:.*\/v(.+)/\1/ip' | tr -d '\r'
98+
}
99+
100+
export DEBIAN_FRONTEND="noninteractive"
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/usr/bin/env bash
2+
3+
set -e
4+
5+
# Optional: Import test library bundled with the devcontainer CLI
6+
# shellcheck source=/dev/null
7+
source dev-container-features-test-lib
8+
9+
# Feature-specific tests
10+
check "version" bash -c "shellcheck --version | grep 0.8.0"
11+
check "which shellcheck" bash -c "which shellcheck | grep /usr/bin/shellcheck"
12+
13+
# Report result
14+
reportResults

test/shellcheck/install-bookworm.sh

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/usr/bin/env bash
2+
3+
set -e
4+
5+
# Optional: Import test library bundled with the devcontainer CLI
6+
# shellcheck source=/dev/null
7+
source dev-container-features-test-lib
8+
9+
# Feature-specific tests
10+
check "version" shellcheck --version
11+
check "which shellcheck" bash -c "which shellcheck | grep /usr/bin/shellcheck"
12+
13+
# Report result
14+
reportResults
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/usr/bin/env bash
2+
3+
set -e
4+
5+
# Optional: Import test library bundled with the devcontainer CLI
6+
# shellcheck source=/dev/null
7+
source dev-container-features-test-lib
8+
9+
# Feature-specific tests
10+
check "version" bash -c "shellcheck --version | grep 0.8.0"
11+
check "which shellcheck" bash -c "which shellcheck | grep /usr/bin/shellcheck"
12+
13+
# Report result
14+
reportResults

test/shellcheck/install-jammy.sh

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/usr/bin/env bash
2+
3+
set -e
4+
5+
# Optional: Import test library bundled with the devcontainer CLI
6+
# shellcheck source=/dev/null
7+
source dev-container-features-test-lib
8+
9+
# Feature-specific tests
10+
check "version" shellcheck --version
11+
check "which shellcheck" bash -c "which shellcheck | grep /usr/local/bin/shellcheck"
12+
13+
# Report result
14+
reportResults

test/shellcheck/scenarios.json

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,35 @@
11
{
2-
"shellcheck-version": {
3-
"image": "debian:latest",
2+
"install-bookworm": {
3+
"image": "debian:bookworm",
4+
"features": {
5+
"shellcheck": {}
6+
}
7+
},
8+
9+
"install-bookworm-with-options": {
10+
"image": "debian:bookworm",
11+
"features": {
12+
"shellcheck": {
13+
"version": "0.8.0",
14+
"installPath": "/usr/bin"
15+
}
16+
}
17+
},
18+
19+
"install-jammy": {
20+
"image": "ubuntu:jammy",
421
"features": {
522
"shellcheck": {
6-
"version": "0.8.0"
23+
"version": "latest"
724
}
825
}
926
},
1027

11-
"shellcheck-install-path": {
12-
"image": "debian:latest",
28+
"install-jammy-with-options": {
29+
"image": "ubuntu:jammy",
1330
"features": {
1431
"shellcheck": {
32+
"version": "0.8.0",
1533
"installPath": "/usr/bin"
1634
}
1735
}

test/shellcheck/shellcheck-version.sh

Lines changed: 0 additions & 18 deletions
This file was deleted.

test/shellcheck/test.sh

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,14 @@
11
#!/usr/bin/env bash
22

3-
# This test file will be executed against an auto-generated devcontainer.json that
4-
# includes the 'shellcheck' Feature with no options.
5-
#
6-
# For more information, see: https://github.com/devcontainers/cli/blob/main/docs/features/test.md
7-
#
8-
# Eg:
9-
# {
10-
# "image": "<..some-base-image...>",
11-
# "features": {
12-
# "shellcheck": {}
13-
# },
14-
# "remoteUser": "root"
15-
# }
16-
#
17-
# Thus, the value of all options will fall back to the default value in the
18-
# Feature's 'devcontainer-feature.json'.
19-
#
20-
# These scripts are run as 'root' by default. Although that can be changed
21-
# with the '--remote-user' flag.
22-
#
23-
# This test can be run with the following command:
24-
#
25-
# devcontainer features test \
26-
# --features shellcheck \
27-
# --remote-user root \
28-
# --skip-scenarios \
29-
# --base-image mcr.microsoft.com/devcontainers/base:ubuntu \
30-
# /path/to/this/repo
31-
323
set -e
334

345
# Optional: Import test library bundled with the devcontainer CLI
35-
# See https://github.com/devcontainers/cli/blob/HEAD/docs/features/test.md#dev-container-features-test-lib
36-
# Provides the 'check' and 'reportResults' commands.
376
# shellcheck source=/dev/null
387
source dev-container-features-test-lib
398

409
# Feature-specific tests
41-
# The 'check' command comes from the dev-container-features-test-lib. Syntax is...
42-
# check <LABEL> <cmd> [args...]
4310
check "version" shellcheck --version
4411
check "which shellcheck" bash -c "which shellcheck | grep /usr/bin/shellcheck"
4512

4613
# Report result
47-
# If any of the checks above exited with a non-zero exit code, the test will fail.
4814
reportResults

0 commit comments

Comments
 (0)