#!/usr/bin/env bash

###################################################
# Downstream Vendor Utility
###################################################
# This script will attempt to vendor the latest
# version of labkit into downstream projects
#
# This script should only be run on master (for now)
# It assumed that the person executing the script
# has Git+SSH push access to GitLab repositories on
# gitlab.com
#
# A new merge request will be created for each
# downstream project
###################################################

set -euo pipefail
IFS=$'\n\t'

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "${SCRIPT_DIR}"

declare -A DOWNSTREAM_PROJECTS=(
  ["gitlab-org/gitlab"]="workhorse"
  ["gitlab-org/gitaly"]=""
  ["gitlab-org/gitlab-pages"]=""
  ["gitlab-org/gitlab-shell"]=""
  ["gitlab-org/container-registry"]=""
  ["gitlab-org/cluster-integration/gitlab-agent"]=""
)

MERGE_REQUESTS=()

LABKIT_VERSION_TAG=$(git describe --tags --abbrev=0)

WORKING_DIR=$(mktemp -d)
trap '{ rm -rf "${WORKING_DIR}"; }' EXIT
pushd "${WORKING_DIR}"

# Pushes to a remote and returns the GitLab Merge Request IID
function git_push_and_return_merge_request_iid() {
  # This could be done more elegantly with gnu-grep, but we can't assume that
  # everyone user (macos users mainly) will have it
  git push "$@" 2>&1 >/dev/null | grep /merge_requests/ | sed 's#.*/merge_requests/##;s# ##g'
}

# Fetch the description from the Releases API
function get_labkit_release_summary() {
  curl --silent --fail \
    "https://gitlab.com/api/v4/projects/gitlab-org%2flabkit/releases/${LABKIT_VERSION_TAG}" |
    jq -r '.description' |
    grep -v '^#' |
    grep -v '^$'
}

function vendor_downstream_project() {
  local project=$1
  local subdir=$2
  local path=${project##*/}
  local branch_name="vendor-$LABKIT_VERSION_TAG"
  local vendor_branch_exists
  local merge_request_iid
  local requires_amend=no
  local summary

  echo "# cloning ${project}"

  git clone "git@gitlab.com:${project}.git" "${path}"
  pushd "${path}/${subdir}"

  if git ls-remote --exit-code --heads origin "${branch_name}"; then
    vendor_branch_exists=yes
    git checkout -b "${branch_name}" "origin/${branch_name}"
  else
    vendor_branch_exists=no
    git checkout -b "${branch_name}"
  fi

  # Update to the appropriate commit SHA
  go get -u=patch "gitlab.com/gitlab-org/labkit@$LABKIT_VERSION_TAG"
  go mod tidy -compat=1.18
  git add go.mod go.sum

  if [[ "$vendor_branch_exists" == "yes" ]]; then
    git commit --amend --no-edit
    merge_request_iid=$(git_push_and_return_merge_request_iid --force-with-lease)
    echo "# updated merge request https://gitlab.com/${project}/-/merge_requests/${merge_request_iid}"
  else
    summary=$(get_labkit_release_summary)

    git commit -m "Update LabKit library to $LABKIT_VERSION_TAG

${summary}

See https://gitlab.com/gitlab-org/labkit/-/releases/$LABKIT_VERSION_TAG"

    merge_request_iid=$(
      git_push_and_return_merge_request_iid \
        -o merge_request.create \
        -o merge_request.target=master \
        -o merge_request.remove_source_branch \
        --set-upstream origin "$(git rev-parse --abbrev-ref HEAD)"
    )

    echo "# created merge request https://gitlab.com/${project}/-/merge_requests/${merge_request_iid}"
  fi

  MERGE_REQUESTS+=("https://gitlab.com/${project}/-/merge_requests/${merge_request_iid}")

  # Add a changelog entry?
  if [[ -x _support/changelog ]]; then
    if _support/changelog \
      --merge-request "${merge_request_iid}" \
      --type other \
      "Update LabKit to $LABKIT_VERSION_TAG"; then
      requires_amend=yes
      git add "changelogs/unreleased/*"
    fi
  fi

  ## Temporary hack until we come up with a better solution
  if [[ "$project" == "gitlab-org/cluster-integration/gitlab-agent" ]]; then
    if make update-repos; then
      requires_amend=yes
      git status
      git add "build/*"
    fi
  fi

  if [[ "$requires_amend" == "yes" ]]; then
    git commit --amend --no-edit
    git push --force-with-lease
  fi

  popd
}

for project in "${!DOWNSTREAM_PROJECTS[@]}"; do
  vendor_downstream_project "${project}" "${DOWNSTREAM_PROJECTS[$project]}"
done

echo "####################################"
echo "# completed successfully"
for mr_url in "${MERGE_REQUESTS[@]}"; do
  echo "# ${mr_url}"
done
