assemble-docker-tags.sh 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. #!/bin/bash
  2. ###################################################
  3. # Usage: assemble-docker-tags.sh --variation <variation> --os <os> --patch-version <patch-version> [--stable-release --github-release-tag <tag>]
  4. ###################################################
  5. # This scripts dives deep into the advanced logic of assembling Docker tags for GitHub Actions.
  6. # If $CI is "true", it outputs the tags to GITHUB_ENV for use in subsequent steps.
  7. # You can run this locally for debugging. The script has beautiful output and can help debug
  8. # any advanced logic issues.
  9. #
  10. # πŸ‘‰ REQUIRED FILES
  11. # - PHP_VERSIONS_FILE must be valid and set to a valid file path
  12. # (defaults to scripts/conf/php-versions.yml)
  13. set -oe pipefail
  14. ##########################
  15. # Environment Settings
  16. # Required variables to set
  17. DEFAULT_IMAGE_VARIATION="${DEFAULT_IMAGE_VARIATION:-"cli"}"
  18. PHP_VERSIONS_FILE="${PHP_VERSIONS_FILE:-"scripts/conf/php-versions.yml"}"
  19. # Convert comma-separated DOCKER_REGISTRY_REPOSITORIES string to an array
  20. IFS=',' read -ra DOCKER_REGISTRY_REPOSITORIES <<< "${DOCKER_REGISTRY_REPOSITORIES:-"docker.io/serversideup/php,ghcr.io/serversideup/php"}"
  21. DOCKER_TAG_PREFIX="${DOCKER_TAG_PREFIX:-""}"
  22. RELEASE_TYPE="${RELEASE_TYPE:-"testing"}"
  23. ##########################
  24. # Functions
  25. # UI Colors
  26. function ui_set_yellow {
  27. printf $'\033[1;33m'
  28. }
  29. function ui_set_green {
  30. printf $'\033[1;32m'
  31. }
  32. function ui_set_red {
  33. printf $'\033[0;31m'
  34. }
  35. function ui_set_blue {
  36. printf $'\033[1;34m'
  37. }
  38. function ui_reset_colors {
  39. printf "\e[0m"
  40. }
  41. function echo_color_message (){
  42. color=$1
  43. message=$2
  44. ui_set_$color
  45. echo "$message"
  46. ui_reset_colors
  47. }
  48. check_vars() {
  49. message=$1
  50. shift
  51. for variable in "$@"; do
  52. if [ -z "${!variable}" ]; then
  53. echo_color_message red "$message: $variable"
  54. echo
  55. help_menu
  56. return 1
  57. fi
  58. done
  59. return 0
  60. }
  61. add_docker_tag() {
  62. # Function: add_docker_tag
  63. # Description: Appends Docker tags to the DOCKER_TAGS variable and prints each tag.
  64. #
  65. # Parameters:
  66. # docker_tag_suffix - The suffix to be appended to the Docker image name as part of the tag.
  67. docker_tag_suffix=$1
  68. for image_name in "${DOCKER_REGISTRY_REPOSITORIES[@]}"; do
  69. # Append a dash to tags that have a suffix
  70. if [[ -n "$DOCKER_TAG_PREFIX" && "$docker_tag_suffix" != "$DOCKER_TAG_PREFIX" ]]; then
  71. prefix_tag="$DOCKER_TAG_PREFIX-"
  72. else
  73. prefix_tag=""
  74. fi
  75. tag_name="$image_name:$prefix_tag$docker_tag_suffix"
  76. if [[ -z "$DOCKER_TAGS" ]]; then
  77. # Do not prefix with comma
  78. DOCKER_TAGS+="$tag_name"
  79. else
  80. # Add a comma to separate the tags
  81. DOCKER_TAGS+=",$tag_name"
  82. fi
  83. # Trim commas for a better output
  84. echo_color_message blue "🐳 Set tag: ${tag_name//,} "
  85. if [[ -n "$GITHUB_RELEASE_TAG" && "$GITHUB_REF_TYPE" == "tag" && "$docker_tag_suffix" != "latest" ]]; then
  86. release_tag_name="$image_name:$docker_tag_suffix-$GITHUB_RELEASE_TAG"
  87. DOCKER_TAGS+=",$release_tag_name"
  88. echo_color_message blue "🐳 Set tag: $release_tag_name"
  89. fi
  90. done
  91. }
  92. function is_latest_stable_patch_within_build_minor() {
  93. [[ "$build_patch_version" == "$latest_patch_within_build_minor" && "$build_patch_version" != *"rc"* ]]
  94. }
  95. function is_latest_global_patch() {
  96. [[ "$build_patch_version" == $latest_patch_global && "$build_patch_version" != *"rc"* ]]
  97. }
  98. function is_latest_minor_within_build_major() {
  99. [[ "$build_minor_version" == "$latest_minor_within_build_major" && "$build_minor_version" != *"rc"* ]]
  100. }
  101. function is_latest_major() {
  102. [[ "$build_major_version" == "$latest_global_stable_major" ]]
  103. }
  104. function is_default_base_os() {
  105. [[ "$build_base_os" == "$default_base_os_within_build_minor" ]]
  106. }
  107. function ci_release_is_production_launch() {
  108. [[ -z "$DOCKER_TAG_PREFIX" && "$RELEASE_TYPE" == "latest" ]]
  109. }
  110. function is_default_variation() {
  111. [[ "$PHP_BUILD_VARIATION" == "$DEFAULT_IMAGE_VARIATION" ]]
  112. }
  113. help_menu() {
  114. echo "Usage: $0 --variation <variation> --os <os> --patch-version <patch-version> [--stable-release --github-release-tag <tag>]"
  115. echo
  116. echo "This script dives deep into the advanced logic of assembling Docker tags for GitHub Actions."
  117. echo "If \$CI is 'true', it outputs the tags to GITHUB_ENV for use in subsequent steps."
  118. echo "You can run this locally for debugging. The script has beautiful output and can help debug"
  119. echo "any advanced logic issues."
  120. echo
  121. echo "Options:"
  122. echo " --variation <variation> Set the PHP variation (e.g., apache, fpm)"
  123. echo " --os <os> Set the base OS (e.g., bullseye, bookworm, alpine)"
  124. echo " --patch-version <patch-version> Set the PHP patch version (e.g., 7.4.10)"
  125. echo " --github-release-tag <tag> Set the GitHub release tag"
  126. echo " --stable-release Flag the tags for a stable release"
  127. echo
  128. echo "Environment Variables (Defaults):"
  129. echo " DEFAULT_IMAGE_VARIATION The default PHP image variation (default: cli)"
  130. echo " DOCKER_REGISTRY_REPOSITORIES Names of images to tag (default: 'docker.io/serversideup/php' 'ghcr.io/serversideup/php')"
  131. echo " PHP_VERSIONS_FILE Path to PHP versions file (default: scripts/conf/php-versions.yml)"
  132. }
  133. ##########################
  134. # Main Script
  135. # Check arguments (if passed, these arguments are optional and intended for development debugging only)
  136. while [[ $# -gt 0 ]]; do
  137. case $1 in
  138. --variation)
  139. PHP_BUILD_VARIATION="$2"
  140. shift 2
  141. ;;
  142. --os)
  143. PHP_BUILD_BASE_OS="$2"
  144. shift 2
  145. ;;
  146. --patch-version)
  147. PHP_BUILD_VERSION="$2"
  148. shift 2
  149. ;;
  150. --github-release-tag)
  151. GITHUB_REF_TYPE="tag"
  152. GITHUB_RELEASE_TAG="$2"
  153. shift 2
  154. ;;
  155. --stable-release)
  156. RELEASE_TYPE="latest"
  157. shift
  158. ;;
  159. *)
  160. echo "πŸ›‘ ERROR: Unknown argument passed: $1"
  161. exit 1
  162. shift
  163. ;;
  164. esac
  165. done
  166. # Check that all required variables are set
  167. check_vars \
  168. "🚨 Required variables not set" \
  169. PHP_BUILD_VARIATION \
  170. PHP_BUILD_VERSION \
  171. PHP_BUILD_BASE_OS \
  172. PHP_VERSIONS_FILE
  173. if [[ ! -f $PHP_VERSIONS_FILE ]]; then
  174. echo_color_message red "🚨 PHP Versions file not found at $PHP_VERSIONS_FILE"
  175. echo "Current directory: $(pwd)"
  176. echo "Contents of $(dirname "$PHP_VERSIONS_FILE"): $(ls -al "$(dirname "$PHP_VERSIONS_FILE")")"
  177. echo "Contents of the file:"
  178. cat "$PHP_VERSIONS_FILE"
  179. exit 1
  180. fi
  181. # Store arguments
  182. build_patch_version=$PHP_BUILD_VERSION
  183. build_base_os=$PHP_BUILD_BASE_OS
  184. build_variation=$PHP_BUILD_VARIATION
  185. # Extract major and minor versions from build_patch_version
  186. build_major_version="${build_patch_version%%.*}"
  187. build_minor_version="${build_patch_version%.*}"
  188. # Fetch version data from the PHP Versions file
  189. latest_global_stable_major=$(yq -o=json "$PHP_VERSIONS_FILE" | jq -r '[.php_versions[] | select(.major | test("-rc") | not) | .major | tonumber] | max | tostring')
  190. 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')
  191. 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')
  192. 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(".")')
  193. 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(".")')
  194. 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')
  195. check_vars \
  196. "🚨 Missing critical build variable. Check the script logic and logs" \
  197. build_patch_version \
  198. build_major_version \
  199. build_minor_version \
  200. latest_global_stable_major \
  201. latest_global_stable_minor \
  202. latest_minor_within_build_major
  203. echo_color_message green "⚑️ PHP Build Version: $build_patch_version"
  204. echo_color_message yellow "πŸ‘‡ Calculated Build Versions:"
  205. echo "Build Major Version: $build_major_version"
  206. echo "Build Minor Version: $build_minor_version"
  207. echo_color_message yellow "🧐 Queried results from $PHP_VERSIONS_FILE"
  208. echo "Latest Global Major Version: $latest_global_stable_major"
  209. echo "Latest Global Minor Version: $latest_global_stable_minor"
  210. echo "Latest Minor Version within Build Major: $latest_minor_within_build_major"
  211. echo "Latest Patch Version within Build Minor: $latest_patch_within_build_minor"
  212. echo "Default Base OS within Build Minor: $default_base_os_within_build_minor"
  213. echo "Latest Global Patch Version: $latest_patch_global"
  214. # Set default tag
  215. DOCKER_TAGS=""
  216. add_docker_tag "$build_patch_version-$build_variation-$build_base_os"
  217. if is_default_base_os; then
  218. add_docker_tag "$build_patch_version-$build_variation"
  219. fi
  220. if is_latest_stable_patch_within_build_minor; then
  221. add_docker_tag "$build_minor_version-$build_variation-$build_base_os"
  222. if is_default_base_os; then
  223. add_docker_tag "$build_minor_version-$build_variation"
  224. fi
  225. if is_default_variation; then
  226. add_docker_tag "$build_minor_version-$build_base_os"
  227. fi
  228. if is_default_base_os && is_default_variation; then
  229. add_docker_tag "$build_minor_version"
  230. fi
  231. if is_latest_minor_within_build_major; then
  232. add_docker_tag "$build_major_version-$build_variation-$build_base_os"
  233. if is_default_base_os; then
  234. add_docker_tag "$build_major_version-$build_variation"
  235. fi
  236. if is_default_variation; then
  237. add_docker_tag "$build_major_version-$build_base_os"
  238. fi
  239. if is_default_base_os && is_default_variation; then
  240. add_docker_tag "$build_major_version"
  241. fi
  242. fi
  243. if is_latest_global_patch; then
  244. add_docker_tag "$build_variation-$build_base_os"
  245. if is_default_variation; then
  246. add_docker_tag "$build_base_os"
  247. fi
  248. if is_default_base_os; then
  249. add_docker_tag "$build_variation"
  250. fi
  251. if is_default_base_os && is_default_variation; then
  252. if ci_release_is_production_launch; then
  253. add_docker_tag "latest"
  254. elif [[ -n "$DOCKER_TAG_PREFIX" ]]; then
  255. add_docker_tag "$DOCKER_TAG_PREFIX"
  256. fi
  257. fi
  258. fi
  259. fi
  260. echo_color_message green "πŸš€ Summary of Docker Tags Being Shipped: $DOCKER_TAGS"
  261. # Save to GitHub's environment
  262. if [[ $CI == "true" ]]; then
  263. echo "DOCKER_TAGS=${DOCKER_TAGS}" >> $GITHUB_ENV
  264. echo_color_message green "βœ… Saved Docker Tags to "GITHUB_ENV""
  265. fi