Skip to content

Commit

Permalink
Refactor actionlint feature (#4)
Browse files Browse the repository at this point in the history
Now that I've built a few of these things and had more time to reference
existing projects, I've tried out these updates with a focus on what
could be made reusable. Especially that new `shared.lib.sh` file that
extracts _stuff_ out that'll be common across Features.

The script itself will need to be duplicated because of the way in which
Features work and are built and deployed. But, at least it tidies up the
actual script needed to install a thing.
  • Loading branch information
jgarber623-cargosense authored Mar 1, 2024
2 parents 99659fe + 28ca9e7 commit 3ca31c4
Show file tree
Hide file tree
Showing 12 changed files with 227 additions and 91 deletions.
2 changes: 1 addition & 1 deletion src/actionlint/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@ Install [actionlint](https://github.com/rhysd/actionlint), a static checker for

## OS Support

This Feature should work on recent versions of Debian/Ubuntu and Linux distributions using the [apt](https://wiki.debian.org/AptCLI) management tool.
This Feature should work on recent versions of Debian/Ubuntu, RedHat Enterprise Linux, Fedora, Alma, and RockyLinux distributions with the `apt`, `yum`, `dnf`, or `microdnf` package manager installed.

`bash` is required to execute the `install.sh` script.
2 changes: 1 addition & 1 deletion src/actionlint/devcontainer-feature.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "actionlint",
"id": "actionlint",
"version": "1.0.0",
"version": "1.1.0",
"description": "Install actionlint, a static checker for GitHub Actions workflow files.",
"options": {
"version": {
Expand Down
59 changes: 43 additions & 16 deletions src/actionlint/install.sh
Original file line number Diff line number Diff line change
@@ -1,27 +1,54 @@
#!/usr/bin/env sh
#!/usr/bin/env bash

set -e

ACTIONLINT_VERSION="${VERSION:-"latest"}"
INSTALL_PATH="${INSTALLPATH:-"/usr/local/bin"}"
ACTIONLINT_INSTALL_PATH="${INSTALLPATH:-"/usr/local/bin"}"
ACTIONLINT_REPOSITORY="https://github.com/rhysd/actionlint"

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

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

if ! type curl >/dev/null 2>&1; then
apt update --yes
apt install --no-install-recommends --yes curl ca-certificates
# shellcheck source=./src/actionlint/shared.lib.sh
. "${SCRIPT_DIR}"/shared.lib.sh

curl_installed="true"
if type actionlint > /dev/null 2>&1; then
echo "Detected existing system install: $(actionlint --version)"
clean_up
exit 0
fi

curl -sSL https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash | \
/bin/bash -s -- "${ACTIONLINT_VERSION}" "${INSTALL_PATH}"
check_packages curl ca-certificates

if ! [ -z $curl_installed ]; then
apt purge curl --autoremove --yes
if [[ "${ACTIONLINT_VERSION}" = "latest" ]]; then
ACTIONLINT_VERSION=$(set -e; latest_release_version "${ACTIONLINT_REPOSITORY}")
fi

machine="$(uname -m)"
case "${machine}" in
x86_64)
arch="amd64"
;;
i?86)
arch="386"
;;
aarch64|arm64)
arch="arm64"
;;
arm*)
arch="armv6"
;;
*)
echo "Could not determine arch from machine hardware name '${machine}'" >&2
exit 1
;;
esac

# https://github.com/rhysd/actionlint/releases/download/v1.0.0/actionlint_1.0.0_linux_386.tar.gz
url="${ACTIONLINT_REPOSITORY}/releases/download/v${ACTIONLINT_VERSION}/actionlint_${ACTIONLINT_VERSION}_linux_${arch}.tar.gz"

echo "Downloading ${url} with curl..."

curl -L "${url}" | tar xvz -C "${ACTIONLINT_INSTALL_PATH}" actionlint

echo "Done!"
100 changes: 100 additions & 0 deletions src/actionlint/shared.lib.sh
Original file line number Diff line number Diff line change
@@ -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"
17 changes: 0 additions & 17 deletions test/actionlint/actionlint-install-path.sh

This file was deleted.

17 changes: 0 additions & 17 deletions test/actionlint/actionlint-version.sh

This file was deleted.

14 changes: 14 additions & 0 deletions test/actionlint/install-bookworm-with-settings.sh
Original file line number Diff line number Diff line change
@@ -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 "actionlint --version | grep 1.6.20"
check "which actionlint" bash -c "which actionlint | grep /usr/bin/actionlint"

# Report result
reportResults
14 changes: 14 additions & 0 deletions test/actionlint/install-bookworm.sh
Original file line number Diff line number Diff line change
@@ -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" actionlint --version
check "which actionlint" bash -c "which actionlint | grep /usr/local/bin/actionlint"

# Report result
reportResults
14 changes: 14 additions & 0 deletions test/actionlint/install-jammy-with-settings.sh
Original file line number Diff line number Diff line change
@@ -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 "actionlint --version | grep 1.6.20"
check "which actionlint" bash -c "which actionlint | grep /usr/bin/actionlint"

# Report result
reportResults
14 changes: 14 additions & 0 deletions test/actionlint/install-jammy.sh
Original file line number Diff line number Diff line change
@@ -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" actionlint --version
check "which actionlint" bash -c "which actionlint | grep /usr/local/bin/actionlint"

# Report result
reportResults
30 changes: 25 additions & 5 deletions test/actionlint/scenarios.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,37 @@
{
"actionlint-version": {
"image": "debian:latest",
"install-bookworm": {
"image": "debian:bookworm",
"features": {
"actionlint": {
"version": "1.6.20"
"version": "latest"
}
}
},

"actionlint-install-path": {
"image": "debian:latest",
"install-bookworm-with-settings": {
"image": "debian:bookworm",
"features": {
"actionlint": {
"version": "1.6.20",
"installPath": "/usr/bin"
}
}
},

"install-jammy": {
"image": "ubuntu:jammy",
"features": {
"actionlint": {
"version": "latest"
}
}
},

"install-jammy-with-settings": {
"image": "ubuntu:jammy",
"features": {
"actionlint": {
"version": "1.6.20",
"installPath": "/usr/bin"
}
}
Expand Down
35 changes: 1 addition & 34 deletions test/actionlint/test.sh
Original file line number Diff line number Diff line change
@@ -1,47 +1,14 @@
#!/usr/bin/env bash

# This test file will be executed against an auto-generated devcontainer.json that
# includes the 'actionlint' Feature with no options.
#
# For more information, see: https://github.com/devcontainers/cli/blob/main/docs/features/test.md
#
# Eg:
# {
# "image": "<..some-base-image...>",
# "features": {
# "actionlint": {}
# },
# "remoteUser": "root"
# }
#
# Thus, the value of all options will fall back to the default value in the
# Feature's 'devcontainer-feature.json'.
#
# These scripts are run as 'root' by default. Although that can be changed
# with the '--remote-user' flag.
#
# This test can be run with the following command:
#
# devcontainer features test \
# --features actionlint \
# --remote-user root \
# --skip-scenarios \
# --base-image mcr.microsoft.com/devcontainers/base:ubuntu \
# /path/to/this/repo

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 <LABEL> <cmd> [args...]
check "version" actionlint --version
check "which actionlint" bash -c "which actionlint | grep /usr/local/bin/actionlint"

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

0 comments on commit 3ca31c4

Please sign in to comment.