push 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. #!/bin/bash
  2. echo ">>> Pushing images..."
  3. export DOCKER_CLI_EXPERIMENTAL=enabled
  4. declare -A annotations=(
  5. [amd64]="--os linux --arch amd64"
  6. [arm32v6]="--os linux --arch arm --variant v6"
  7. [arm32v7]="--os linux --arch arm --variant v7"
  8. [arm64v8]="--os linux --arch arm64 --variant v8"
  9. )
  10. source ./hooks/arches.sh
  11. set -ex
  12. declare -A images
  13. for arch in ${arches[@]}; do
  14. images[$arch]="${DOCKER_REPO}:${DOCKER_TAG}-${arch}"
  15. done
  16. # Push the images that were just built; manifest list creation fails if the
  17. # images (manifests) referenced don't already exist in the Docker registry.
  18. for image in "${images[@]}"; do
  19. docker push "${image}"
  20. done
  21. manifest_lists=("${DOCKER_REPO}:${DOCKER_TAG}")
  22. # If the Docker tag starts with a version number, assume the latest release is
  23. # being pushed. Add an extra manifest (`latest-release` or `alpine-release`,
  24. # as appropriate) to make it easier to track the latest release.
  25. if [[ "${DOCKER_TAG}" =~ ^[0-9]+\.[0-9]+\.[0-9]+ ]]; then
  26. if [[ "${DOCKER_TAG}" == *alpine ]]; then
  27. manifest_lists+=(${DOCKER_REPO}:alpine-release)
  28. else
  29. manifest_lists+=(${DOCKER_REPO}:latest-release)
  30. fi
  31. fi
  32. for manifest_list in "${manifest_lists[@]}"; do
  33. # Create the (multi-arch) manifest list of arch-specific images.
  34. docker manifest create ${manifest_list} ${images[@]}
  35. # Make sure each image manifest is annotated with the correct arch info.
  36. # Docker does not auto-detect the arch of each cross-compiled image, so
  37. # everything would appear as `linux/amd64` otherwise.
  38. for arch in "${arches[@]}"; do
  39. docker manifest annotate ${annotations[$arch]} ${manifest_list} ${images[$arch]}
  40. done
  41. # Push the manifest list.
  42. docker manifest push --purge ${manifest_list}
  43. done
  44. # Avoid logging credentials and tokens.
  45. set +ex
  46. # Delete the arch-specific tags, if credentials for doing so are available.
  47. # Note that `DOCKER_PASSWORD` must be the actual user password. Passing a JWT
  48. # obtained using a personal access token results in a 403 error with
  49. # {"detail": "access to the resource is forbidden with personal access token"}
  50. if [[ -z "${DOCKER_USERNAME}" || -z "${DOCKER_PASSWORD}" ]]; then
  51. exit 0
  52. fi
  53. # Given a JSON input on stdin, extract the string value associated with the
  54. # specified key. This avoids an extra dependency on a tool like `jq`.
  55. extract() {
  56. local key="$1"
  57. # Extract "<key>":"<val>" (assumes key/val won't contain double quotes).
  58. # The colon may have whitespace on either side.
  59. grep -o "\"${key}\"[[:space:]]*:[[:space:]]*\"[^\"]\+\"" |
  60. # Extract just <val> by deleting the last '"', and then greedily deleting
  61. # everything up to '"'.
  62. sed -e 's/"$//' -e 's/.*"//'
  63. }
  64. echo ">>> Getting API token..."
  65. jwt=$(curl -sS -X POST \
  66. -H "Content-Type: application/json" \
  67. -d "{\"username\":\"${DOCKER_USERNAME}\",\"password\": \"${DOCKER_PASSWORD}\"}" \
  68. "https://hub.docker.com/v2/users/login" |
  69. extract 'token')
  70. # Strip the registry portion from `index.docker.io/user/repo`.
  71. repo="${DOCKER_REPO#*/}"
  72. for arch in ${arches[@]}; do
  73. tag="${DOCKER_TAG}-${arch}"
  74. echo ">>> Deleting '${repo}:${tag}'..."
  75. curl -sS -X DELETE \
  76. -H "Authorization: Bearer ${jwt}" \
  77. "https://hub.docker.com/v2/repositories/${repo}/tags/${tag}/"
  78. done