Add shellcheck to catch bad shell code

This commit is contained in:
James Westby
2019-10-04 15:13:14 +01:00
committed by James Westby
parent 449decc476
commit 6309b17069
5 changed files with 52 additions and 40 deletions
+2 -2
View File
@@ -1,6 +1,6 @@
language: bash language: bash
sudo: required sudo: required
script: sudo bash buildall script: bash shellcheck && sudo bash buildall
dist: xenial dist: xenial
services: services:
- docker - docker
@@ -13,7 +13,7 @@ before_install:
sleep 1 sleep 1
done done
- sudo apt-get -qq update - sudo apt-get -qq update
- sudo apt-get install -y debian-archive-keyring debootstrap - sudo apt-get install -y debian-archive-keyring debootstrap shellcheck
deploy: deploy:
provider: script provider: script
script: bash pushall script: bash pushall
+20 -20
View File
@@ -47,11 +47,11 @@ log() {
build() { build() {
DIST=$1 DIST=$1
[ -f debootstrap/$DIST ] || (echo "buildall: Unknown distribution: $DIST" && exit 1) [ -f "debootstrap/$DIST" ] || (echo "buildall: Unknown distribution: $DIST" && exit 1)
current_ts="$(date -u +%Y-%m-%dT%H:%M:%S.%NZ)" current_ts="$(date -u +%Y-%m-%dT%H:%M:%S.%NZ)"
if docker pull $BASENAME:$DIST > /dev/null; then if docker pull "$BASENAME:$DIST" > /dev/null; then
target_ts="$(docker inspect $BASENAME:$DIST | jq --raw-output ".[0].Created")" target_ts="$(docker inspect "$BASENAME:$DIST" | jq --raw-output ".[0].Created")"
pulled_image_id="$(docker inspect $BASENAME:$DIST | jq --raw-output ".[0].Id")" pulled_image_id="$(docker inspect "$BASENAME:$DIST" | jq --raw-output ".[0].Id")"
else else
target_ts="$current_ts" target_ts="$current_ts"
pulled_image_id= pulled_image_id=
@@ -59,46 +59,46 @@ build() {
log "============================================" log "============================================"
log "Building $BASENAME:$DIST" log "Building $BASENAME:$DIST"
log "============================================" log "============================================"
./mkimage build/$DIST.tar $DIST ./mkimage "build/$DIST.tar" "$DIST"
built_image_id=$(./import build/$DIST.tar "$target_ts") built_image_id=$(./import "build/$DIST.tar" "$target_ts")
log "============================================" log "============================================"
log "Running tests for $BASENAME:$DIST" log "Running tests for $BASENAME:$DIST"
log "============================================" log "============================================"
./test $built_image_id $DIST ./test "$built_image_id" "$DIST"
log "============================================" log "============================================"
log "Rebuilding $BASENAME:$DIST to test reproducibility" log "Rebuilding $BASENAME:$DIST to test reproducibility"
log "============================================" log "============================================"
./mkimage build/${DIST}-repro.tar $DIST ./mkimage "build/${DIST}-repro.tar" "$DIST"
repro_image_id=$(./import build/${DIST}-repro.tar "$target_ts") repro_image_id=$(./import "build/${DIST}-repro.tar" "$target_ts")
if [ "$repro_image_id" != "$built_image_id" ]; then if [ "$repro_image_id" != "$built_image_id" ]; then
log "$BASENAME:$DIST differs after a rebuild. Examine $built_image_id and $repro_image_id" log "$BASENAME:$DIST differs after a rebuild. Examine $built_image_id and $repro_image_id"
log "to find the differences and fix the build to be reproducible again." log "to find the differences and fix the build to be reproducible again."
log "Changes (- first build, + second build):" log "Changes (- first build, + second build):"
./dockerdiff $built_image_id $repro_image_id || true ./dockerdiff "$built_image_id" "$repro_image_id" || true
exit 1 exit 1
fi fi
rm build/${DIST}-repro.tar rm "build/${DIST}-repro.tar"
if [ -n "$pulled_image_id" ]; then if [ -n "$pulled_image_id" ]; then
if [ "$built_image_id" != "$pulled_image_id" ]; then if [ "$built_image_id" != "$pulled_image_id" ]; then
log "Image changed $built_image_id (new) != $pulled_image_id (old)" log "Image changed $built_image_id (new) != $pulled_image_id (old)"
log "Changes (- old, + new):" log "Changes (- old, + new):"
./dockerdiff $pulled_image_id $built_image_id || true ./dockerdiff "$pulled_image_id" "$built_image_id" || true
# Re-import with the current timestamp so that the image shows # Re-import with the current timestamp so that the image shows
# as new # as new
built_image_id="$(./import build/$DIST.tar "$current_ts")" built_image_id="$(./import "build/$DIST.tar" "$current_ts")"
else else
log "Image didn't change" log "Image didn't change"
return return
fi fi
fi fi
docker tag $built_image_id $BASENAME:$DIST docker tag "$built_image_id" "$BASENAME:$DIST"
docker tag $built_image_id $QUAY_BASENAME:$DIST docker tag "$built_image_id" "$QUAY_BASENAME:$DIST"
docker tag $built_image_id $GCR_BASENAME:$DIST docker tag "$built_image_id" "$GCR_BASENAME:$DIST"
log "Tagged $built_image_id as $BASENAME:$DIST $QUAY_BASENAME:$DIST $GCR_BASENAME:$DIST" log "Tagged $built_image_id as $BASENAME:$DIST $QUAY_BASENAME:$DIST $GCR_BASENAME:$DIST"
if [ "$DIST" == "$LATEST" ]; then if [ "$DIST" == "$LATEST" ]; then
docker tag $BASENAME:$DIST $BASENAME:latest docker tag "$BASENAME:$DIST" "$BASENAME:latest"
docker tag $QUAY_BASENAME:$DIST $QUAY_BASENAME:latest docker tag "$QUAY_BASENAME:$DIST" "$QUAY_BASENAME:latest"
docker tag $GCR_BASENAME:$DIST $GCR_BASENAME:latest docker tag "$GCR_BASENAME:$DIST" "$GCR_BASENAME:latest"
fi fi
} }
@@ -107,4 +107,4 @@ if [ -z "$1" ]; then
exit 1 exit 1
fi fi
build $1 build "$1"
+14 -12
View File
@@ -3,26 +3,26 @@ set -e
set -u set -u
set -o pipefail set -o pipefail
ROOT=$(cd $(dirname $0) && pwd) ROOT=$(cd "$(dirname "$0")" && pwd)
TARGET=${1:?Specify the target filename} TARGET=${1:?Specify the target filename}
DIST=${2:-stable} DIST=${2:-stable}
LOGFILE=${TARGET}.log LOGFILE=${TARGET}.log
>$LOGFILE :>"$LOGFILE"
exec > >(tee -ia $LOGFILE) exec > >(tee -ia "$LOGFILE")
exec 2> >(tee -ia $LOGFILE >&2) exec 2> >(tee -ia "$LOGFILE" >&2)
DEBOOTSTRAP_DIR=$(mktemp -d) DEBOOTSTRAP_DIR=$(mktemp -d)
cp -a /usr/share/debootstrap/* $DEBOOTSTRAP_DIR cp -a /usr/share/debootstrap/* "$DEBOOTSTRAP_DIR"
cp -a /usr/share/keyrings/debian-archive-keyring.gpg $DEBOOTSTRAP_DIR cp -a /usr/share/keyrings/debian-archive-keyring.gpg "$DEBOOTSTRAP_DIR"
cp -a $ROOT/debootstrap/* $DEBOOTSTRAP_DIR/scripts cp -a "${ROOT}/debootstrap/"* "${DEBOOTSTRAP_DIR}/scripts"
KEYRING=$DEBOOTSTRAP_DIR/debian-archive-keyring.gpg KEYRING=$DEBOOTSTRAP_DIR/debian-archive-keyring.gpg
if [ -f $ROOT/keys/$DIST.gpg ]; then if [ -f "${ROOT}/keys/${DIST}.gpg" ]; then
gpg --no-default-keyring --keyring $KEYRING --import $ROOT/keys/$DIST.gpg gpg --no-default-keyring --keyring "$KEYRING" --import "${ROOT}/keys/${DIST}.gpg"
fi fi
export DEBIAN_FRONTEND=noninteractive export DEBIAN_FRONTEND=noninteractive
@@ -37,7 +37,7 @@ DIRS_TO_TRIM="/usr/share/man
rootfsDir=$(mktemp -d) rootfsDir=$(mktemp -d)
echo "Building base in $rootfsDir" echo "Building base in $rootfsDir"
DEBOOTSTRAP_DIR=$DEBOOTSTRAP_DIR debootstrap --keyring $KEYRING --variant container --foreign ${DIST} "$rootfsDir" DEBOOTSTRAP_DIR="$DEBOOTSTRAP_DIR" debootstrap --keyring "$KEYRING" --variant container --foreign "${DIST}" "$rootfsDir"
chroot "$rootfsDir" bash debootstrap/debootstrap --second-stage chroot "$rootfsDir" bash debootstrap/debootstrap --second-stage
echo -e "deb http://deb.debian.org/debian $DIST main" > "$rootfsDir/etc/apt/sources.list" echo -e "deb http://deb.debian.org/debian $DIST main" > "$rootfsDir/etc/apt/sources.list"
@@ -212,11 +212,11 @@ echo "host" > "$rootfsDir/etc/hostname"
# Capture the most recent date that a package in the image was changed. # Capture the most recent date that a package in the image was changed.
# We don't care about the particular date, or which package it comes from, # We don't care about the particular date, or which package it comes from,
# we just need a date that isn't very far in the past. # we just need a date that isn't very far in the past.
BUILD_DATE="$(find $rootfsDir/usr/share/doc -name changelog.Debian.gz -exec dpkg-parsechangelog -SDate -l'{}' \; | xargs -l -i date --date="{}" +%s | sort -n | tail -n 1)" BUILD_DATE="$(find "$rootfsDir/usr/share/doc" -name changelog.Debian.gz -print0 | xargs -0 -n1 -I{} dpkg-parsechangelog -SDate -l'{}' | xargs -l -i date --date="{}" +%s | sort -n | tail -n 1)"
echo "Trimming down" echo "Trimming down"
for DIR in $DIRS_TO_TRIM; do for DIR in $DIRS_TO_TRIM; do
rm -r "$rootfsDir/$DIR"/* rm -r "${rootfsDir:?rootfsDir cannot be empty}/$DIR"/*
done done
# Remove the aux-cache as it isn't reproducible. It doesn't seem to # Remove the aux-cache as it isn't reproducible. It doesn't seem to
# cause any problems to remove it. # cause any problems to remove it.
@@ -231,6 +231,8 @@ find "$rootfsDir" -depth -newermt "@$BUILD_DATE" -print0 | xargs -0r touch --no-
echo "Total size" echo "Total size"
du -skh "$rootfsDir" du -skh "$rootfsDir"
echo "Package sizes" echo "Package sizes"
# these aren't shell variables, this is a template, so override sc thinking these are the wrong type of quotes
# shellcheck disable=SC2016
chroot "$rootfsDir" dpkg-query -W -f '${Package} ${Installed-Size}\n' chroot "$rootfsDir" dpkg-query -W -f '${Package} ${Installed-Size}\n'
echo "Largest dirs" echo "Largest dirs"
du "$rootfsDir" | sort -n | tail -n 20 du "$rootfsDir" | sort -n | tail -n 20
+8 -6
View File
@@ -27,7 +27,7 @@ if [ -n "${GCR_KEY:-}" ]; then
fi fi
ENABLE_DOCKER_CONTENT_TRUST=0 ENABLE_DOCKER_CONTENT_TRUST=0
if [ -n "${DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE:-}" -a -n "${DOCKER_CONTENT_TRUST_REPOSITORY_KEY:-}" ]; then if [ -n "${DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE:-}" ] && [ -n "${DOCKER_CONTENT_TRUST_REPOSITORY_KEY:-}" ]; then
tmpdir=$(mktemp -d) tmpdir=$(mktemp -d)
(cd "${tmpdir}" && bash -c 'echo -n "${DOCKER_CONTENT_TRUST_REPOSITORY_KEY}" | base64 -d > key') (cd "${tmpdir}" && bash -c 'echo -n "${DOCKER_CONTENT_TRUST_REPOSITORY_KEY}" | base64 -d > key')
chmod 400 "${tmpdir}/key" chmod 400 "${tmpdir}/key"
@@ -44,11 +44,13 @@ done
# Create and merge a PR to update minideb-extras # Create and merge a PR to update minideb-extras
CIRCLE_CI_FUNCTIONS_URL=${CIRCLE_CI_FUNCTIONS_URL:-https://raw.githubusercontent.com/bitnami/test-infra/master/circle/functions} CIRCLE_CI_FUNCTIONS_URL=${CIRCLE_CI_FUNCTIONS_URL:-https://raw.githubusercontent.com/bitnami/test-infra/master/circle/functions}
source <(curl -sSL $CIRCLE_CI_FUNCTIONS_URL) # sc can't follow source as it is a remote file
# shellcheck disable=SC1090
source <(curl -sSL "$CIRCLE_CI_FUNCTIONS_URL")
for DIST in $DISTS; do for DIST in $DISTS; do
# Use '.RepoDigests 0' for getting Dockerhub repo digest as it was the first pushed # Use '.RepoDigests 0' for getting Dockerhub repo digest as it was the first pushed
DIST_REPO_DIGEST=$(docker image inspect --format '{{index .RepoDigests 0}}' ${BASENAME}:${DIST}) DIST_REPO_DIGEST=$(docker image inspect --format '{{index .RepoDigests 0}}' "${BASENAME}:${DIST}")
update_minideb_derived "https://github.com/bitnami/minideb-extras" $DIST $DIST_REPO_DIGEST update_minideb_derived "https://github.com/bitnami/minideb-extras" "$DIST" "$DIST_REPO_DIGEST"
update_minideb_derived "https://github.com/bitnami/minideb-extras-base" $DIST $DIST_REPO_DIGEST update_minideb_derived "https://github.com/bitnami/minideb-extras-base" "$DIST" "$DIST_REPO_DIGEST"
update_minideb_derived "https://github.com/bitnami/minideb-runtimes" $DIST $DIST_REPO_DIGEST update_minideb_derived "https://github.com/bitnami/minideb-runtimes" "$DIST" "$DIST_REPO_DIGEST"
done done
Executable
+8
View File
@@ -0,0 +1,8 @@
#!/bin/bash
set -eu
set -o pipefail
SCRIPTS=(shellcheck mkimage buildone buildall pushall)
shellcheck -s bash "${SCRIPTS[@]}"