#!/bin/bash

set -e

# This script builds an image that contains assets, that's then used by:
# - The `CNG` downstream pipelines (triggered from `gitlab-org/gitlab` via the `review-build-cng` job):
#   https://gitlab.com/gitlab-org/gitlab/-/blob/c34e0834b01cd45c1f69a01b5e38dd6bc505f903/.gitlab/ci/review-apps/main.gitlab-ci.yml#L69.
# - The `omnibus-gitlab` downstream pipelines (triggered from `gitlab-org/gitlab` via the `e2e:test-on-omnibus-ee` job):
#   https://gitlab.com/gitlab-org/omnibus-gitlab/-/blob/dfd1ad475868fc84e91ab7b5706aa03e46dc3a86/.gitlab-ci.yml#L130.
# - The `gitlab-org/charts/gitlab` `master` pipelines via `gitlab-org/build/CNG`,
#   which pull `registry.gitlab.com/gitlab-org/gitlab/gitlab-assets-ee:master`
# - The `omnibus-gitlab` and CNG `master`/stable-branch pipelines, for both gitlab.com and dev.gitlab.org,
#   which pull `registry.gitlab.com/gitlab-org/gitlab/gitlab-assets-ee:${CI_COMMIT_REF_SLUG}`.
# - The `omnibus-gitlab` tag pipelines, for both gitlab.com and dev.gitlab.org,
#   which pull `registry.gitlab.com/gitlab-org/gitlab/gitlab-assets-ee:${CI_COMMIT_REF_SLUG}`.
# - The CNG tag pipelines, for both gitlab.com and dev.gitlab.org,
#   which pull `registry.gitlab.com/gitlab-org/gitlab/gitlab-assets-ee:${CI_COMMIT_REF_NAME}`.
# - The auto-deploy pipelines, which pull `registry.gitlab.com/gitlab-org/gitlab/gitlab-assets-ee:${CI_COMMIT_SHA}`.

# Exit early if we don't want to build the image
if [ "${GLCI_BUILD_ASSETS_IMAGE}" != "true" ]; then
  echo "GLCI_BUILD_ASSETS_IMAGE: ${GLCI_BUILD_ASSETS_IMAGE}. Skipping assets image build."
  exit 0
fi

# Asset images are only built in canonical namespace
if [[ ! $CI_PROJECT_NAMESPACE =~ ^gitlab(-org|-cn)?($|\/) ]]; then
  echo "Asset image build is only supported in canonical namespaces. Skipping assets image build."
  exit 0
fi

source "$(dirname "$0")/utils.sh"

# Generate the image name based on the project this is being run in
ASSETS_IMAGE_NAME="gitlab-assets-ce"

# `dev.gitlab-org` still has gitlab-ee.
if ([ "${CI_PROJECT_NAME}" = "gitlab" ] && [ "${FOSS_ONLY}" != "1" ]) || ([ "${CI_PROJECT_NAME}" = "gitlab-ee" ] && [ "${FOSS_ONLY}" != "1" ]); then
  ASSETS_IMAGE_NAME="gitlab-assets-ee"
fi

# Generate this image for https://jihulab.com/gitlab-cn/gitlab
if [ "${CI_PROJECT_NAMESPACE}" = "gitlab-cn" ]; then
  ASSETS_IMAGE_NAME="gitlab-assets-jh"
fi

ASSETS_IMAGE_PATH="${CI_REGISTRY}/${CI_PROJECT_PATH}/${ASSETS_IMAGE_NAME}"

# Used in MR pipelines
COMMIT_ASSETS_HASH_DESTINATION="${ASSETS_IMAGE_PATH}:$(assets_image_tag)"
# Used by other projects's master pipelines
COMMIT_REF_SLUG_DESTINATION="${ASSETS_IMAGE_PATH}:${CI_COMMIT_REF_SLUG}"
# Used by auto-deploy pipelines: https://gitlab.com/gitlab-org/release/docs/blob/master/general/deploy/auto-deploy.md
COMMIT_SHA_DESTINATION=${ASSETS_IMAGE_PATH}:${CI_COMMIT_SHA}
# Used for CNG tag pipelines
COMMIT_REF_NAME_DESTINATION="${ASSETS_IMAGE_PATH}:${CI_COMMIT_REF_NAME}"

# Instrumented assets must never occupy the tags plain pipelines consume
if [[ "${BABEL_ENV}" == "istanbul" ]]; then
  DESTINATIONS=""
else
  DESTINATIONS="--tag=${COMMIT_REF_SLUG_DESTINATION} --tag=${COMMIT_SHA_DESTINATION}"
  if [ -n "${CI_COMMIT_TAG}" ]; then
    DESTINATIONS="$DESTINATIONS --tag=${COMMIT_REF_NAME_DESTINATION}"
  fi
fi

LAYOUT_LABEL_KEY="org.gitlab.assets-image.layout"

# Whether to reuse the image already on the assets-hash tag instead of building a new one. Only if:
# - GLCI_REBUILD_ASSETS_IMAGE isn't "true".
# - The existing image was built for the same bundlers. It's labelled with GLCI_ASSETS_IMAGE_LAYOUT,
#   for example "rspack", and an image built for different bundlers is missing assets.
# - The job pushes no other tags, or this is an MR pipeline that isn't a merge train. Any pipeline can
#   push the assets-hash tag, so deploy pipelines and merge trains (whose commit becomes the master
#   commit) build their own image. A reused image never gets the SHA or ref tags that deploys pull.
function can_reuse_existing_image() {
  [ "${GLCI_REBUILD_ASSETS_IMAGE}" != "true" ] || return 1
  [ -n "${GLCI_ASSETS_IMAGE_LAYOUT}" ] || return 1
  if [ -n "${DESTINATIONS}" ]; then
    [ -n "${CI_MERGE_REQUEST_IID}" ] || return 1
    [ "${CI_MERGE_REQUEST_EVENT_TYPE}" != "merge_train" ] || return 1
  fi

  docker buildx imagetools inspect --format '{{json .Image}}' "${COMMIT_ASSETS_HASH_DESTINATION}" 2>/dev/null \
    | tr -d '[:space:]' \
    | grep -qF "\"${LAYOUT_LABEL_KEY}\":\"${GLCI_ASSETS_IMAGE_LAYOUT}\""
}

if can_reuse_existing_image; then
  echosuccess "Image ${COMMIT_ASSETS_HASH_DESTINATION} already exists with layout ${GLCI_ASSETS_IMAGE_LAYOUT}, reusing it" "yes"
else
  echoinfo "Image ${COMMIT_ASSETS_HASH_DESTINATION} can't be reused, rebuilding" "yes"

  DESTINATIONS="${DESTINATIONS} --tag=${COMMIT_ASSETS_HASH_DESTINATION}"
  LABELS=""
  if [ -n "${GLCI_ASSETS_IMAGE_LAYOUT}" ]; then
    LABELS="--label=${LAYOUT_LABEL_KEY}=${GLCI_ASSETS_IMAGE_LAYOUT}"
  fi
  build_dir=assets_container.build
  mkdir -p $build_dir/public
  cp -r public/assets ${build_dir}/public/
  cp Dockerfile.assets ${build_dir}/

  docker buildx build --file Dockerfile.assets --platform "${ARCH:-linux/amd64}" ${DESTINATIONS} ${LABELS} --push $build_dir
fi
