#!/bin/bash ################################################### # Usage: assemble-docker-tags.sh --variation --os --patch-version [--stable-release --github-release-tag ] ################################################### # This scripts dives deep into the advanced logic of assembling Docker tags for GitHub Actions. # If $CI is "true", it outputs the tags to GITHUB_ENV for use in subsequent steps. # You can run this locally for debugging. The script has beautiful output and can help debug # any advanced logic issues. # # 👉 REQUIRED FILES # - PHP_VERSIONS_FILE must be valid and set to a valid file path # (defaults to scripts/conf/php-versions.yml) set -oe pipefail ########################## # Environment Settings # Required variables to set DEFAULT_IMAGE_VARIATION="${DEFAULT_IMAGE_VARIATION:-"cli"}" PHP_VERSIONS_FILE="${PHP_VERSIONS_FILE:-"scripts/conf/php-versions.yml"}" # Convert comma-separated DOCKER_REGISTRY_REPOSITORIES string to an array IFS=',' read -ra DOCKER_REGISTRY_REPOSITORIES <<< "${DOCKER_REGISTRY_REPOSITORIES:-"docker.io/serversideup/php,ghcr.io/serversideup/php"}" DOCKER_TAG_PREFIX="${DOCKER_TAG_PREFIX:-""}" RELEASE_TYPE="${RELEASE_TYPE:-"testing"}" ########################## # Functions # UI Colors function ui_set_yellow { printf $'\033[1;33m' } function ui_set_green { printf $'\033[1;32m' } function ui_set_red { printf $'\033[0;31m' } function ui_set_blue { printf $'\033[1;34m' } function ui_reset_colors { printf "\e[0m" } function echo_color_message (){ color=$1 message=$2 ui_set_$color echo "$message" ui_reset_colors } check_vars() { message=$1 shift for variable in "$@"; do if [ -z "${!variable}" ]; then echo_color_message red "$message: $variable" echo help_menu return 1 fi done return 0 } add_docker_tag() { # Function: add_docker_tag # Description: Appends Docker tags to the DOCKER_TAGS variable and prints each tag. # # Parameters: # docker_tag_suffix - The suffix to be appended to the Docker image name as part of the tag. docker_tag_suffix=$1 for image_name in "${DOCKER_REGISTRY_REPOSITORIES[@]}"; do # Append a dash to tags that have a suffix if [[ -n "$DOCKER_TAG_PREFIX" && "$docker_tag_suffix" != "$DOCKER_TAG_PREFIX" ]]; then prefix_tag="$DOCKER_TAG_PREFIX-" else prefix_tag="" fi tag_name="$image_name:$prefix_tag$docker_tag_suffix" if [[ -z "$DOCKER_TAGS" ]]; then # Do not prefix with comma DOCKER_TAGS+="$tag_name" else # Add a comma to separate the tags DOCKER_TAGS+=",$tag_name" fi # Trim commas for a better output echo_color_message blue "🐳 Set tag: ${tag_name//,} " if [[ -n "$GITHUB_RELEASE_TAG" && "$GITHUB_REF_TYPE" == "tag" && "$docker_tag_suffix" != "latest" ]]; then release_tag_name="$image_name:$docker_tag_suffix-$GITHUB_RELEASE_TAG" DOCKER_TAGS+=",$release_tag_name" echo_color_message blue "🐳 Set tag: $release_tag_name" fi done } function is_latest_stable_patch_within_build_minor() { [[ "$build_patch_version" == "$latest_patch_within_build_minor" && "$build_patch_version" != *"rc"* ]] } function is_latest_global_patch() { [[ "$build_patch_version" == $latest_patch_global && "$build_patch_version" != *"rc"* ]] } function is_latest_minor_within_build_major() { [[ "$build_minor_version" == "$latest_minor_within_build_major" && "$build_minor_version" != *"rc"* ]] } function is_latest_major() { [[ "$build_major_version" == "$latest_global_stable_major" ]] } function is_default_base_os() { [[ "$build_base_os" == "$default_base_os_within_build_minor" ]] } function ci_release_is_production_launch() { [[ -z "$DOCKER_TAG_PREFIX" && "$RELEASE_TYPE" == "latest" ]] } function is_default_variation() { [[ "$PHP_BUILD_VARIATION" == "$DEFAULT_IMAGE_VARIATION" ]] } help_menu() { echo "Usage: $0 --variation --os --patch-version [--stable-release --github-release-tag ]" echo echo "This script dives deep into the advanced logic of assembling Docker tags for GitHub Actions." echo "If \$CI is 'true', it outputs the tags to GITHUB_ENV for use in subsequent steps." echo "You can run this locally for debugging. The script has beautiful output and can help debug" echo "any advanced logic issues." echo echo "Options:" echo " --variation Set the PHP variation (e.g., apache, fpm)" echo " --os Set the base OS (e.g., bullseye, bookworm, alpine)" echo " --patch-version Set the PHP patch version (e.g., 7.4.10)" echo " --github-release-tag Set the GitHub release tag" echo " --stable-release Flag the tags for a stable release" echo echo "Environment Variables (Defaults):" echo " DEFAULT_IMAGE_VARIATION The default PHP image variation (default: cli)" echo " DOCKER_REGISTRY_REPOSITORIES Names of images to tag (default: 'docker.io/serversideup/php' 'ghcr.io/serversideup/php')" echo " PHP_VERSIONS_FILE Path to PHP versions file (default: scripts/conf/php-versions.yml)" } ########################## # Main Script # Check arguments (if passed, these arguments are optional and intended for development debugging only) while [[ $# -gt 0 ]]; do case $1 in --variation) PHP_BUILD_VARIATION="$2" shift 2 ;; --os) PHP_BUILD_BASE_OS="$2" shift 2 ;; --patch-version) PHP_BUILD_VERSION="$2" shift 2 ;; --github-release-tag) GITHUB_REF_TYPE="tag" GITHUB_RELEASE_TAG="$2" shift 2 ;; --stable-release) RELEASE_TYPE="latest" shift ;; *) echo "🛑 ERROR: Unknown argument passed: $1" exit 1 shift ;; esac done # Check that all required variables are set check_vars \ "🚨 Required variables not set" \ PHP_BUILD_VARIATION \ PHP_BUILD_VERSION \ PHP_BUILD_BASE_OS \ PHP_VERSIONS_FILE if [[ ! -f $PHP_VERSIONS_FILE ]]; then echo_color_message red "🚨 PHP Versions file not found at $PHP_VERSIONS_FILE" echo "Current directory: $(pwd)" echo "Contents of $(dirname "$PHP_VERSIONS_FILE"): $(ls -al "$(dirname "$PHP_VERSIONS_FILE")")" echo "Contents of the file:" cat "$PHP_VERSIONS_FILE" exit 1 fi # Store arguments build_patch_version=$PHP_BUILD_VERSION build_base_os=$PHP_BUILD_BASE_OS build_variation=$PHP_BUILD_VARIATION # Extract major and minor versions from build_patch_version build_major_version="${build_patch_version%%.*}" build_minor_version="${build_patch_version%.*}" # Fetch version data from the PHP Versions file latest_global_stable_major=$(yq -o=json "$PHP_VERSIONS_FILE" | jq -r '[.php_versions[] | select(.major | test("-rc") | not) | .major | tonumber] | max | tostring') latest_global_stable_minor=$(yq -o=json "$PHP_VERSIONS_FILE" | jq -r --arg latest_global_stable_major "$latest_global_stable_major" '.php_versions[] | select(.major == $latest_global_stable_major) | .minor_versions | map(select(.minor | test("-rc") | not) | .minor | split(".") | .[1] | tonumber) | max | $latest_global_stable_major + "." + tostring') latest_minor_within_build_major=$(yq -o=json "$PHP_VERSIONS_FILE" | jq -r --arg build_major "$build_major_version" '.php_versions[] | select(.major == $build_major) | .minor_versions | map(select(.minor | test("-rc") | not) | .minor | split(".") | .[1] | tonumber) | max | $build_major + "." + tostring') latest_patch_within_build_minor=$(yq -o=json "$PHP_VERSIONS_FILE" | jq -r --arg build_minor "$build_minor_version" '.php_versions[] | .minor_versions[] | select(.minor == $build_minor) | .patch_versions | map( split(".") | map(tonumber) ) | max | join(".")') latest_patch_global=$(yq -o=json "$PHP_VERSIONS_FILE" | jq -r '[.php_versions[] | .minor_versions[] | select(.minor | test("-rc") | not) | .patch_versions[] | select(test("-rc") | not) | split(".") | map(tonumber) ] | max | join(".")') default_base_os_within_build_minor=$(yq -o=json "$PHP_VERSIONS_FILE" | jq -r --arg build_minor "$build_minor_version" '.php_versions[] | .minor_versions[] | select(.minor == $build_minor) | .base_os[] | select(.default == true) | .name') check_vars \ "🚨 Missing critical build variable. Check the script logic and logs" \ build_patch_version \ build_major_version \ build_minor_version \ latest_global_stable_major \ latest_global_stable_minor \ latest_minor_within_build_major echo_color_message green "⚡️ PHP Build Version: $build_patch_version" echo_color_message yellow "👇 Calculated Build Versions:" echo "Build Major Version: $build_major_version" echo "Build Minor Version: $build_minor_version" echo_color_message yellow "🧐 Queried results from $PHP_VERSIONS_FILE" echo "Latest Global Major Version: $latest_global_stable_major" echo "Latest Global Minor Version: $latest_global_stable_minor" echo "Latest Minor Version within Build Major: $latest_minor_within_build_major" echo "Latest Patch Version within Build Minor: $latest_patch_within_build_minor" echo "Default Base OS within Build Minor: $default_base_os_within_build_minor" echo "Latest Global Patch Version: $latest_patch_global" # Set default tag DOCKER_TAGS="" add_docker_tag "$build_patch_version-$build_variation-$build_base_os" if is_default_base_os; then add_docker_tag "$build_patch_version-$build_variation" fi if is_latest_stable_patch_within_build_minor; then add_docker_tag "$build_minor_version-$build_variation-$build_base_os" if is_default_base_os; then add_docker_tag "$build_minor_version-$build_variation" fi if is_default_variation; then add_docker_tag "$build_minor_version-$build_base_os" fi if is_default_base_os && is_default_variation; then add_docker_tag "$build_minor_version" fi if is_latest_minor_within_build_major; then add_docker_tag "$build_major_version-$build_variation-$build_base_os" if is_default_base_os; then add_docker_tag "$build_major_version-$build_variation" fi if is_default_variation; then add_docker_tag "$build_major_version-$build_base_os" fi if is_default_base_os && is_default_variation; then add_docker_tag "$build_major_version" fi fi if is_latest_global_patch; then add_docker_tag "$build_variation-$build_base_os" if is_default_variation; then add_docker_tag "$build_base_os" fi if is_default_base_os; then add_docker_tag "$build_variation" fi if is_default_base_os && is_default_variation; then if ci_release_is_production_launch; then add_docker_tag "latest" elif [[ -n "$DOCKER_TAG_PREFIX" ]]; then add_docker_tag "$DOCKER_TAG_PREFIX" fi fi fi fi echo_color_message green "🚀 Summary of Docker Tags Being Shipped: $DOCKER_TAGS" # Save to GitHub's environment if [[ $CI == "true" ]]; then echo "DOCKER_TAGS=${DOCKER_TAGS}" >> $GITHUB_ENV echo_color_message green "✅ Saved Docker Tags to "GITHUB_ENV"" fi