test-pr.sh 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. #!/bin/bash
  2. set -eo pipefail
  3. # TODO something clever with this pattern to get the exact list of _tags_ which have changed, not just repos:
  4. #format='{{ range .Entries }}{{ join " " (join ":" $.RepoName (.Tags | first)) .GitRepo .GitFetch .GitCommit .Directory }}{{ "\n" }}{{ end }}'
  5. #comm -13 \
  6. # <(bashbrew cat -f "$format" https://github.com/docker-library/official-images/raw/master/library/docker | sort) \
  7. # <(bashbrew cat -f "$format" https://raw.githubusercontent.com/infosiftr/stackbrew/d92ffa4b5f8a558c22c5d0a7e0f33bff8fae990b/library/docker | sort) \
  8. # | cut -d' ' -f1
  9. # make sure we can GTFO
  10. trap 'echo >&2 Ctrl+C captured, exiting; exit 1' SIGINT
  11. # start with an error if Docker isn't working...
  12. docker version > /dev/null
  13. dir="$(dirname "$(readlink -f "$BASH_SOURCE")")"
  14. usage() {
  15. cat <<-EOUSAGE
  16. usage: $0 [PR number] [repo[:tag]]
  17. ie: $0 1024
  18. $0 9001 debian php django
  19. $0 0 hylang # special case that runs against local directory
  20. This script builds and tests the specified pull request to official-images and
  21. provides ouput in markdown for commenting on the pull request.
  22. EOUSAGE
  23. }
  24. pull="$1"
  25. shift || { usage >&2 && exit 1; }
  26. if [ -z "$BASHBREW_SECOND_STAGE" ]; then
  27. dockerRepo='oisupport/bashbrew'
  28. dockerBase="$dockerRepo:base"
  29. dockerImage="$dockerRepo:test-pr"
  30. bashbrewVersion="$(< "$dir/bashbrew-version")"
  31. docker build -t "$dockerBase" --pull "https://github.com/docker-library/bashbrew.git#v$bashbrewVersion" > /dev/null
  32. docker build -t "$dockerImage" "$dir" > /dev/null
  33. args=( --init )
  34. if [ "$pull" = '0' ]; then
  35. args+=( --name "bashbrew-test-local-$RANDOM" )
  36. else
  37. args+=( --name "bashbrew-test-pr-$pull" )
  38. fi
  39. args+=(
  40. -v /var/run/docker.sock:/var/run/docker.sock
  41. --group-add 0
  42. -v /etc/passwd:/etc/passwd:ro
  43. -v /etc/group:/etc/group:ro
  44. )
  45. if getent group docker &> /dev/null; then
  46. args+=( --group-add "$(getent group docker | cut -d: -f3)" )
  47. fi
  48. # if we don't have DOCKER_HOST set, let's bind-mount cache for speed!
  49. if [ -z "$DOCKER_HOST" ]; then
  50. export BASHBREW_CACHE="${BASHBREW_CACHE:-${XDG_CACHE_HOME:-$HOME/.cache}/bashbrew}" # resolve path to current "host-side" cache directory
  51. mkdir -p "$BASHBREW_CACHE" # ensure it's created by our user, not root
  52. export BASHBREW_CACHE="$(cd "$BASHBREW_CACHE" && pwd -P)" # readlink -f
  53. args+=(
  54. -v "$BASHBREW_CACHE":/bashbrew-cache
  55. -e BASHBREW_CACHE=/bashbrew-cache
  56. # make sure our user in the container can read it
  57. --group-add "$(stat -c '%g' "$BASHBREW_CACHE")"
  58. )
  59. else
  60. dockerGid="$(
  61. docker run -i --rm "${args[@]}" "$dockerImage" sh -e <<-'EOSH'
  62. exec 2>/dev/null
  63. stat -c '%g' /var/run/docker.sock \
  64. || getent group docker | cut -d: -f3
  65. EOSH
  66. )" || true
  67. if [ "$dockerGid" ]; then
  68. args+=( --group-add "$dockerGid" )
  69. fi
  70. fi
  71. args+=(
  72. --user "$(id -u)":"$(id -g)"
  73. $(id -G | xargs -n1 echo --group-add)
  74. -e BASHBREW_SECOND_STAGE=1
  75. )
  76. for e in "${!BASHBREW_@}"; do
  77. case "$e" in
  78. BASHBREW_SECOND_STAGE|BASHBREW_CACHE|BASHBREW_LIBRARY) ;;
  79. *)
  80. args+=( -e "$e" )
  81. ;;
  82. esac
  83. done
  84. cmd=( ./test-pr.sh "$pull" "$@" )
  85. if [ -t 0 ] && [ -t 1 ]; then
  86. # only add "-t" if we have a TTY
  87. args+=( -t )
  88. fi
  89. exec docker run -i --rm "${args[@]}" "$dockerImage" "${cmd[@]}"
  90. fi
  91. if [ -d .git ]; then
  92. echo >&2 'error: something has gone horribly wrong; .git already exists'
  93. echo >&2 ' why do you have BASHBREW_SECOND_STAGE set?'
  94. exit 1
  95. fi
  96. if [ "$pull" = '0' ]; then
  97. commit='FAKE'
  98. else
  99. dir="$(mktemp -d)"
  100. trap "rm -rf '$dir'" EXIT
  101. cd "$dir"
  102. # TODO we only have "git version 2.4.1" which doesn't support "clone -q" :(
  103. git init -q .
  104. git remote add origin https://github.com/docker-library/official-images.git
  105. git fetch -q origin
  106. git reset -q --hard origin/master
  107. git config user.name 'nobody'
  108. git config user.email '[email protected]'
  109. git fetch -q origin "pull/$pull/head:pr-$pull"
  110. git merge -q --no-edit "pr-$pull" > /dev/null
  111. commit="$(git log -1 --format=format:%h "pr-$pull")"
  112. fi
  113. export BASHBREW_LIBRARY="$PWD/library"
  114. if [ "$#" -eq 0 ]; then
  115. IFS=$'\n'
  116. files=( $(git diff --name-only origin/master...HEAD -- library | xargs -n1 basename) )
  117. unset IFS
  118. # TODO narrow this down into groups of the exact tags for each image that changed >:)
  119. else
  120. files=( "$@" )
  121. fi
  122. if [ ${#files[@]} -eq 0 ]; then
  123. echo >&2 'no files in library/ changed in PR #'"$pull"
  124. exit 0
  125. fi
  126. join() {
  127. sep="$1"
  128. arg1="$2"
  129. shift 2
  130. echo -n "$arg1"
  131. [ $# -gt 0 ] && printf "${sep}%s" "$@"
  132. }
  133. IFS=$'\n'
  134. files=( $(bashbrew list --repos --uniq --build-order "${files[@]}") )
  135. unset IFS
  136. echo 'Build test of' '#'"$pull"';' "$commit"';' '`'"${BASHBREW_ARCH:-amd64}"'`' '(`'"$(join '`, `' "${files[@]}")"'`):'
  137. declare -A failedBuild=() failedTests=()
  138. for img in "${files[@]}"; do
  139. IFS=$'\n'
  140. uniqImgs=( $(bashbrew list --uniq --build-order "$img") )
  141. uniqImgs=( $(bashbrew cat --format '{{ if .TagEntry.HasArchitecture arch }}{{ $.RepoName }}:{{ .TagEntry.Tags | first }}{{ end }}' "${uniqImgs[@]}") ) # filter to just the set supported by the current BASHBREW_ARCH
  142. unset IFS
  143. echo
  144. echo '```console'
  145. for uniqImg in "${uniqImgs[@]}"; do
  146. imgRepo="${uniqImg%%:*}"
  147. echo
  148. echo '$ bashbrew build' "$uniqImg"
  149. if bashbrew build --pull=missing "$uniqImg"; then
  150. echo
  151. echo '$ test/run.sh' "$uniqImg"
  152. if ! ./test/run.sh "$uniqImg"; then
  153. failedTests[$imgRepo]+=" $uniqImg"
  154. fi
  155. else
  156. failedBuild[$imgRepo]+=" $uniqImg"
  157. fi
  158. echo
  159. done
  160. echo '```'
  161. done
  162. echo
  163. if [ "${#failedBuild[@]}" -gt 0 ]; then
  164. echo 'The following images failed to build:'
  165. echo
  166. for repo in "${!failedBuild[@]}"; do
  167. echo '- `'"$repo"'`:'
  168. for img in ${failedBuild[$repo]}; do
  169. echo ' - `'"$img"'`'
  170. done
  171. done
  172. echo
  173. fi
  174. if [ "${#failedTests[@]}" -gt 0 ]; then
  175. echo
  176. echo 'The following images failed at least one test:'
  177. echo
  178. for repo in "${!failedTests[@]}"; do
  179. echo '- `'"$repo"'`:'
  180. for img in ${failedTests[$repo]}; do
  181. echo ' - `'"$img"'`'
  182. done
  183. done
  184. echo
  185. fi