diff --git a/.github/workflows/verify-templating.yml b/.github/workflows/verify-templating.yml new file mode 100644 index 000000000..14497bec6 --- /dev/null +++ b/.github/workflows/verify-templating.yml @@ -0,0 +1,22 @@ +name: Verify Templating + +on: + pull_request: + push: + +defaults: + run: + shell: 'bash -Eeuo pipefail -x {0}' + +jobs: + apply-templates: + name: Check For Uncomitted Changes + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Apply Templates + run: ./apply-templates.sh + - name: Check Git Status + run: | + status="$(git status --short)" + [ -z "$status" ] diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..d548f66de --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.jq-template.awk diff --git a/6.0/alpine/Dockerfile b/6.0/alpine3.18/Dockerfile similarity index 97% rename from 6.0/alpine/Dockerfile rename to 6.0/alpine3.18/Dockerfile index 83bbcd2b4..0b49d6222 100644 --- a/6.0/alpine/Dockerfile +++ b/6.0/alpine3.18/Dockerfile @@ -1,3 +1,9 @@ +# +# NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh" +# +# PLEASE DO NOT EDIT IT DIRECTLY. +# + FROM alpine:3.18 # add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added diff --git a/6.0/alpine/docker-entrypoint.sh b/6.0/alpine3.18/docker-entrypoint.sh similarity index 100% rename from 6.0/alpine/docker-entrypoint.sh rename to 6.0/alpine3.18/docker-entrypoint.sh diff --git a/6.0/Dockerfile b/6.0/bookworm/Dockerfile similarity index 98% rename from 6.0/Dockerfile rename to 6.0/bookworm/Dockerfile index 7eb87156f..8bb149914 100644 --- a/6.0/Dockerfile +++ b/6.0/bookworm/Dockerfile @@ -1,3 +1,9 @@ +# +# NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh" +# +# PLEASE DO NOT EDIT IT DIRECTLY. +# + FROM debian:bookworm-slim # add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added diff --git a/6.0/docker-entrypoint.sh b/6.0/bookworm/docker-entrypoint.sh similarity index 100% rename from 6.0/docker-entrypoint.sh rename to 6.0/bookworm/docker-entrypoint.sh diff --git a/6.2/alpine/Dockerfile b/6.2/alpine3.18/Dockerfile similarity index 97% rename from 6.2/alpine/Dockerfile rename to 6.2/alpine3.18/Dockerfile index 4a22193b4..6df9f342c 100644 --- a/6.2/alpine/Dockerfile +++ b/6.2/alpine3.18/Dockerfile @@ -1,3 +1,9 @@ +# +# NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh" +# +# PLEASE DO NOT EDIT IT DIRECTLY. +# + FROM alpine:3.18 # add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added diff --git a/6.2/alpine/docker-entrypoint.sh b/6.2/alpine3.18/docker-entrypoint.sh similarity index 100% rename from 6.2/alpine/docker-entrypoint.sh rename to 6.2/alpine3.18/docker-entrypoint.sh diff --git a/6.2/Dockerfile b/6.2/bookworm/Dockerfile similarity index 98% rename from 6.2/Dockerfile rename to 6.2/bookworm/Dockerfile index 6f917ad7d..ba483905b 100644 --- a/6.2/Dockerfile +++ b/6.2/bookworm/Dockerfile @@ -1,3 +1,9 @@ +# +# NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh" +# +# PLEASE DO NOT EDIT IT DIRECTLY. +# + FROM debian:bookworm-slim # add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added diff --git a/6.2/docker-entrypoint.sh b/6.2/bookworm/docker-entrypoint.sh similarity index 100% rename from 6.2/docker-entrypoint.sh rename to 6.2/bookworm/docker-entrypoint.sh diff --git a/7.0/alpine/Dockerfile b/7.0/alpine3.18/Dockerfile similarity index 97% rename from 7.0/alpine/Dockerfile rename to 7.0/alpine3.18/Dockerfile index 35e38350e..8b7c49d72 100644 --- a/7.0/alpine/Dockerfile +++ b/7.0/alpine3.18/Dockerfile @@ -1,3 +1,9 @@ +# +# NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh" +# +# PLEASE DO NOT EDIT IT DIRECTLY. +# + FROM alpine:3.18 # add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added diff --git a/7.0/alpine/docker-entrypoint.sh b/7.0/alpine3.18/docker-entrypoint.sh similarity index 100% rename from 7.0/alpine/docker-entrypoint.sh rename to 7.0/alpine3.18/docker-entrypoint.sh diff --git a/7.0/Dockerfile b/7.0/bookworm/Dockerfile similarity index 98% rename from 7.0/Dockerfile rename to 7.0/bookworm/Dockerfile index b7692f7e1..324e8b5e3 100644 --- a/7.0/Dockerfile +++ b/7.0/bookworm/Dockerfile @@ -1,3 +1,9 @@ +# +# NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh" +# +# PLEASE DO NOT EDIT IT DIRECTLY. +# + FROM debian:bookworm-slim # add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added diff --git a/7.0/docker-entrypoint.sh b/7.0/bookworm/docker-entrypoint.sh similarity index 100% rename from 7.0/docker-entrypoint.sh rename to 7.0/bookworm/docker-entrypoint.sh diff --git a/7.2/alpine/Dockerfile b/7.2/alpine3.18/Dockerfile similarity index 97% rename from 7.2/alpine/Dockerfile rename to 7.2/alpine3.18/Dockerfile index 0ab3e3854..66b2d1ca8 100644 --- a/7.2/alpine/Dockerfile +++ b/7.2/alpine3.18/Dockerfile @@ -1,3 +1,9 @@ +# +# NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh" +# +# PLEASE DO NOT EDIT IT DIRECTLY. +# + FROM alpine:3.18 # add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added diff --git a/7.2/alpine/docker-entrypoint.sh b/7.2/alpine3.18/docker-entrypoint.sh similarity index 100% rename from 7.2/alpine/docker-entrypoint.sh rename to 7.2/alpine3.18/docker-entrypoint.sh diff --git a/7.2/Dockerfile b/7.2/bookworm/Dockerfile similarity index 98% rename from 7.2/Dockerfile rename to 7.2/bookworm/Dockerfile index 19eafb4fc..3eabf7c3f 100644 --- a/7.2/Dockerfile +++ b/7.2/bookworm/Dockerfile @@ -1,3 +1,9 @@ +# +# NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh" +# +# PLEASE DO NOT EDIT IT DIRECTLY. +# + FROM debian:bookworm-slim # add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added diff --git a/7.2/docker-entrypoint.sh b/7.2/bookworm/docker-entrypoint.sh similarity index 100% rename from 7.2/docker-entrypoint.sh rename to 7.2/bookworm/docker-entrypoint.sh diff --git a/Dockerfile-alpine.template b/Dockerfile-alpine.template index 4762895ee..a9e5efa92 100644 --- a/Dockerfile-alpine.template +++ b/Dockerfile-alpine.template @@ -1,4 +1,4 @@ -FROM alpine:3.18 +FROM alpine:{{ env.variant | ltrimstr("alpine") }} # add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added RUN addgroup -S -g 1000 redis && adduser -S -G redis -u 999 redis @@ -10,9 +10,9 @@ RUN apk add --no-cache \ # add tzdata for https://github.com/docker-library/redis/issues/138 tzdata -ENV REDIS_VERSION placeholder -ENV REDIS_DOWNLOAD_URL placeholder -ENV REDIS_DOWNLOAD_SHA placeholder +ENV REDIS_VERSION {{ .version }} +ENV REDIS_DOWNLOAD_URL {{ .downloadUrl }} +ENV REDIS_DOWNLOAD_SHA {{ .sha256 }} RUN set -eux; \ \ diff --git a/Dockerfile.template b/Dockerfile.template index 5f0e9db2d..31f2a0656 100644 --- a/Dockerfile.template +++ b/Dockerfile.template @@ -1,11 +1,11 @@ -FROM debian:bookworm-slim +FROM debian:{{ env.variant }}-slim # add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added RUN groupadd -r -g 999 redis && useradd -r -g redis -u 999 redis # grab gosu for easy step-down from root # https://github.com/tianon/gosu/releases -ENV GOSU_VERSION 1.16 +ENV GOSU_VERSION {{ .gosu.version }} RUN set -eux; \ savedAptMark="$(apt-mark showmanual)"; \ apt-get update; \ @@ -26,9 +26,9 @@ RUN set -eux; \ gosu --version; \ gosu nobody true -ENV REDIS_VERSION placeholder -ENV REDIS_DOWNLOAD_URL placeholder -ENV REDIS_DOWNLOAD_SHA placeholder +ENV REDIS_VERSION {{ .version }} +ENV REDIS_DOWNLOAD_URL {{ .downloadUrl }} +ENV REDIS_DOWNLOAD_SHA {{ .sha256 }} RUN set -eux; \ \ diff --git a/apply-templates.sh b/apply-templates.sh new file mode 100755 index 000000000..2edf95f86 --- /dev/null +++ b/apply-templates.sh @@ -0,0 +1,73 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +[ -f versions.json ] # run "versions.sh" first + +cd "$(dirname "$(readlink -f "$BASH_SOURCE")")" + +jqt='.jq-template.awk' +if [ -n "${BASHBREW_SCRIPTS:-}" ]; then + jqt="$BASHBREW_SCRIPTS/jq-template.awk" +elif [ "$BASH_SOURCE" -nt "$jqt" ]; then + # https://github.com/docker-library/bashbrew/blob/master/scripts/jq-template.awk + wget -qO "$jqt" 'https://github.com/docker-library/bashbrew/raw/9f6a35772ac863a0241f147c820354e4008edf38/scripts/jq-template.awk' +fi + +if [ "$#" -eq 0 ]; then + versions="$(jq -r 'keys | map(@sh) | join(" ")' versions.json)" + eval "set -- $versions" +fi + +generated_warning() { + cat <<-EOH + # + # NOTE: THIS DOCKERFILE IS GENERATED VIA "apply-templates.sh" + # + # PLEASE DO NOT EDIT IT DIRECTLY. + # + + EOH +} + +for version; do + export version + + if [ -d "$version" ]; then + rm -rf "$version" + fi + + if jq -e '.[env.version] | not' versions.json > /dev/null; then + echo "skipping $version ..." + continue + fi + + variants="$(jq -r '.[env.version].variants | map(@sh) | join(" ")' versions.json)" + eval "variants=( $variants )" + + for variant in "${variants[@]}"; do + export variant + + echo "processing $version/$variant ..." + + dir="$version${variant:+/$variant}" + + mkdir -p "$dir" + + cp -f docker-entrypoint.sh "$dir/" + + case "$variant" in + alpine*) + template='Dockerfile-alpine.template' + sed -i -e 's/gosu/su-exec/g' "$dir/docker-entrypoint.sh" + ;; + *) + template='Dockerfile.template' + ;; + esac + + { + generated_warning + gawk -f "$jqt" "$template" + } > "$dir/Dockerfile" + done +done diff --git a/update.sh b/update.sh index 7a306d985..bac2d7581 100755 --- a/update.sh +++ b/update.sh @@ -3,69 +3,5 @@ set -Eeuo pipefail cd "$(dirname "$(readlink -f "$BASH_SOURCE")")" -versions=( "$@" ) -if [ ${#versions[@]} -eq 0 ]; then - versions=( */ ) -fi -versions=( "${versions[@]%/}" ) - -packagesUrl='https://raw.githubusercontent.com/redis/redis-hashes/master/README' -packages="$(echo "$packagesUrl" | sed -r 's/[^a-zA-Z.-]+/-/g')" -trap "$(printf 'rm -f %q' "$packages")" EXIT -curl -fsSL "$packagesUrl" -o "$packages" - -for version in "${versions[@]}"; do - rcVersion="${version%-rc}" - - line="$( - awk ' - { gsub(/^redis-|[.]tar[.]gz$/, "", $2) } - $1 == "hash" && $2 ~ /^'"$rcVersion"'([.]|$)/ { print } - ' "$packages" \ - | sort -rV \ - | head -1 - )" - - if [ -n "$line" ]; then - fullVersion="$(cut -d' ' -f2 <<<"$line")" - downloadUrl="$(cut -d' ' -f5 <<<"$line")" - shaHash="$(cut -d' ' -f4 <<<"$line")" - shaType="$(cut -d' ' -f3 <<<"$line")" - elif [ "$version" != "$rcVersion" ] && fullVersion="$( - git ls-remote --tags https://github.com/redis/redis.git "refs/tags/$rcVersion*" \ - | cut -d/ -f3 \ - | cut -d^ -f1 \ - | sort -urV \ - | head -1 - )" && [ -n "$fullVersion" ]; then - downloadUrl="https://github.com/redis/redis/archive/$fullVersion.tar.gz" - shaType='sha256' - shaHash="$(curl -fsSL "$downloadUrl" | "${shaType}sum" | cut -d' ' -f1)" - else - echo >&2 "error: full version for $version cannot be determined" - exit 1 - fi - [ "$shaType" = 'sha256' ] || [ "$shaType" = 'sha1' ] - - echo "$version: $fullVersion" - - for variant in \ - alpine '' \ - ; do - dir="$version${variant:+/$variant}" - [ -d "$dir" ] || continue - template="Dockerfile${variant:+-$variant}.template" - - sed -r \ - -e 's/^(ENV REDIS_VERSION) .*/\1 '"$fullVersion"'/' \ - -e 's!^(ENV REDIS_DOWNLOAD_URL) .*!\1 '"$downloadUrl"'!' \ - -e 's/^(ENV REDIS_DOWNLOAD_SHA) .*/\1 '"$shaHash"'/' \ - -e 's!sha[0-9]+sum!'"$shaType"'sum!g' \ - "$template" > "$dir/Dockerfile" - - cp -a docker-entrypoint.sh "$dir/" - if [ "$variant" = 'alpine' ]; then - sed -i -e 's/gosu/su-exec/g' "$dir/docker-entrypoint.sh" - fi - done -done +./versions.sh "$@" +./apply-templates.sh "$@" diff --git a/versions.json b/versions.json new file mode 100644 index 000000000..98df1b755 --- /dev/null +++ b/versions.json @@ -0,0 +1,58 @@ +{ + "6.0": { + "alpine": "3.18", + "debian": "bookworm", + "downloadUrl": "http://download.redis.io/releases/redis-6.0.20.tar.gz", + "gosu": { + "version": "1.16" + }, + "sha256": "173d4c5f44b5d7186da96c4adc5cb20e8018b50ec3a8dfe0d191dbbab53952f0", + "variants": [ + "bookworm", + "alpine3.18" + ], + "version": "6.0.20" + }, + "6.2": { + "alpine": "3.18", + "debian": "bookworm", + "downloadUrl": "http://download.redis.io/releases/redis-6.2.13.tar.gz", + "gosu": { + "version": "1.16" + }, + "sha256": "89ff27c80d420456a721ccfb3beb7cc628d883c53059803513749e13214a23d1", + "variants": [ + "bookworm", + "alpine3.18" + ], + "version": "6.2.13" + }, + "7.0": { + "alpine": "3.18", + "debian": "bookworm", + "downloadUrl": "http://download.redis.io/releases/redis-7.0.13.tar.gz", + "gosu": { + "version": "1.16" + }, + "sha256": "97065774d5fb8388eb0d8913458decfcb167d356e40d31dd01cd30c1cc391673", + "variants": [ + "bookworm", + "alpine3.18" + ], + "version": "7.0.13" + }, + "7.2": { + "alpine": "3.18", + "debian": "bookworm", + "downloadUrl": "http://download.redis.io/releases/redis-7.2.1.tar.gz", + "gosu": { + "version": "1.16" + }, + "sha256": "5c76d990a1b1c5f949bcd1eed90d0c8a4f70369bdbdcb40288c561ddf88967a4", + "variants": [ + "bookworm", + "alpine3.18" + ], + "version": "7.2.1" + } +} diff --git a/versions.sh b/versions.sh new file mode 100755 index 000000000..5d1ad8109 --- /dev/null +++ b/versions.sh @@ -0,0 +1,124 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +# we will support at most two entries in each of these lists, and both should be in descending order +supportedDebianSuites=( + bookworm +) +supportedAlpineVersions=( + 3.18 +) +defaultDebianSuite="${supportedDebianSuites[0]}" +declare -A debianSuites=( + #[7.2]='3.17' +) +defaultAlpineVersion="${supportedAlpineVersions[0]}" +declare -A alpineVersions=( + #[14]='3.16' +) + +gosuVersion='1.16' + +cd "$(dirname "$(readlink -f "$BASH_SOURCE")")" + +versions=( "$@" ) +if [ ${#versions[@]} -eq 0 ]; then + versions=( */ ) + json='{}' +else + json="$(< versions.json)" +fi +versions=( "${versions[@]%/}" ) + +packagesBase='https://raw.githubusercontent.com/redis/redis-hashes/master/README' + +declare -A packages= + +fetch_package_list() { + local -; set +x # make sure running with "set -x" doesn't spam the terminal with the raw package lists + + # normal (GA) releases end up in the "main" component of upstream's repository + if [ -z "${packages}" ]; then + packages="$(curl -fsSL "$packagesBase")" + fi +} +get_version() { + local version="$1"; shift + + rcVersion="${version%-rc}" + + line="$( + awk ' + { gsub(/^redis-|[.]tar[.]gz$/, "", $2) } + $1 == "hash" && $2 ~ /^'"$rcVersion"'([.]|$)/ { print } + ' <<< "$packages" \ + | sort -rV \ + | head -1 + )" + + if [ -n "$line" ]; then + fullVersion="$(cut -d' ' -f2 <<<"$line")" + downloadUrl="$(cut -d' ' -f5 <<<"$line")" + shaHash="$(cut -d' ' -f4 <<<"$line")" + shaType="$(cut -d' ' -f3 <<<"$line")" + elif [ "$version" != "$rcVersion" ] && fullVersion="$( + git ls-remote --tags https://github.com/redis/redis.git "refs/tags/$rcVersion*" \ + | cut -d/ -f3 \ + | cut -d^ -f1 \ + | sort -urV \ + | head -1 + )" && [ -n "$fullVersion" ]; then + downloadUrl="https://github.com/redis/redis/archive/$fullVersion.tar.gz" + shaType='sha256' + shaHash="$(curl -fsSL "$downloadUrl" | "${shaType}sum" | cut -d' ' -f1)" + else + echo >&2 "error: full version for $version cannot be determined" + exit 1 + fi + [ "$shaType" = 'sha256' ] || [ "$shaType" = 'sha1' ] +} + +for version in "${versions[@]}"; do + export version + + versionAlpineVersion="${alpineVersions[$version]:-$defaultAlpineVersion}" + versionDebianSuite="${debianSuites[$version]-$defaultDebianSuite}" + export versionAlpineVersion versionDebianSuite + + doc="$(jq -nc '{ + alpine: env.versionAlpineVersion, + debian: env.versionDebianSuite, + }')" + + fetch_package_list + get_version "$version" + + for suite in "${supportedDebianSuites[@]}"; do + export suite + doc="$(jq <<<"$doc" -c ' + .variants += [ env.suite ] + ')" + done + + for alpineVersion in "${supportedAlpineVersions[@]}"; do + doc="$(jq <<<"$doc" -c --arg v "$alpineVersion" ' + .variants += [ "alpine" + $v ] + ')" + done + + echo "$version: $fullVersion" + + export fullVersion shaType shaHash downloadUrl gosuVersion + json="$(jq <<<"$json" -c --argjson doc "$doc" ' + .[env.version] = ($doc + { + version: env.fullVersion, + downloadUrl: env.downloadUrl, + (env.shaType): env.shaHash, + "gosu": { + version: env.gosuVersion + } + }) + ')" +done + +jq <<<"$json" -S . > versions.json