1#!/usr/bin/env bash 2# vim: ts=2 et 3# Setting -x is absolutely forbidden as it could leak the GitHub token. 4set -uo pipefail 5 6# GITHUB_TOKEN required scope: repo.repo_public 7 8git_mail="prometheus-team@googlegroups.com" 9git_user="prombot" 10branch="repo_sync_codemirror" 11commit_msg="Update codemirror" 12pr_title="Synchronize codemirror from prometheus/prometheus" 13pr_msg="Propagating changes from prometheus/prometheus default branch." 14target_repo="prometheus-community/codemirror-promql" 15source_path="web/ui/module/codemirror-promql" 16 17color_red='\e[31m' 18color_green='\e[32m' 19color_yellow='\e[33m' 20color_none='\e[0m' 21 22echo_red() { 23 echo -e "${color_red}$@${color_none}" 1>&2 24} 25 26echo_green() { 27 echo -e "${color_green}$@${color_none}" 1>&2 28} 29 30echo_yellow() { 31 echo -e "${color_yellow}$@${color_none}" 1>&2 32} 33 34GITHUB_TOKEN="${GITHUB_TOKEN:-}" 35if [ -z "${GITHUB_TOKEN}" ]; then 36 echo_red 'GitHub token (GITHUB_TOKEN) not set. Terminating.' 37 exit 1 38fi 39 40# List of files that should not be synced. 41excluded_files="CODE_OF_CONDUCT.md LICENSE Makefile.common SECURITY.md .yamllint MAINTAINERS.md" 42excluded_dirs=".github .circleci" 43 44# Go to the root of the repo 45cd "$(git rev-parse --show-cdup)" || exit 1 46 47source_dir="$(pwd)/${source_path}" 48 49tmp_dir="$(mktemp -d)" 50trap 'rm -rf "${tmp_dir}"' EXIT 51 52## Internal functions 53github_api() { 54 local url 55 url="https://api.github.com/${1}" 56 shift 1 57 curl --retry 5 --silent --fail -u "${git_user}:${GITHUB_TOKEN}" "${url}" "$@" 58} 59 60get_default_branch() { 61 github_api "repos/${1}" 2> /dev/null | 62 jq -r .default_branch 63} 64 65push_branch() { 66 local git_url 67 git_url="https://${git_user}:${GITHUB_TOKEN}@github.com/${1}" 68 # stdout and stderr are redirected to /dev/null otherwise git-push could leak 69 # the token in the logs. 70 # Delete the remote branch in case it was merged but not deleted. 71 git push --quiet "${git_url}" ":${branch}" 1>/dev/null 2>&1 72 git push --quiet "${git_url}" --set-upstream "${branch}" 1>/dev/null 2>&1 73} 74 75post_pull_request() { 76 local repo="$1" 77 local default_branch="$2" 78 local post_json 79 post_json="$(printf '{"title":"%s","base":"%s","head":"%s","body":"%s"}' "${pr_title}" "${default_branch}" "${branch}" "${pr_msg}")" 80 echo "Posting PR to ${default_branch} on ${repo}" 81 github_api "repos/${repo}/pulls" --data "${post_json}" --show-error | 82 jq -r '"PR URL " + .html_url' 83} 84 85process_repo() { 86 local org_repo 87 local default_branch 88 org_repo="$1" 89 mkdir -p "${tmp_dir}/${org_repo}" 90 echo_green "Processing '${org_repo}'" 91 92 default_branch="$(get_default_branch "${org_repo}")" 93 if [[ -z "${default_branch}" ]]; then 94 echo "Can't get the default branch." 95 return 96 fi 97 echo "Default branch: ${default_branch}" 98 99 # Clone target repo to temporary directory and checkout to new branch 100 git clone --quiet "https://github.com/${org_repo}.git" "${tmp_dir}/${org_repo}" 101 cd "${tmp_dir}/${org_repo}" || return 1 102 git checkout -b "${branch}" || return 1 103 104 git rm -r . 105 106 cp -ra ${source_dir}/. . 107 git add . 108 109 for excluded_dir in ${excluded_dirs}; do 110 git reset -- "${excluded_dir}/*" 111 git checkout -- "${excluded_dir}/*" 112 done 113 114 for excluded_file in ${excluded_files}; do 115 git reset -- "${excluded_file}" 116 git checkout -- "${excluded_file}" 117 done 118 119 if [[ -n "$(git status --porcelain)" ]]; then 120 git config user.email "${git_mail}" 121 git config user.name "${git_user}" 122 git add . 123 git commit -s -m "${commit_msg}" 124 if push_branch "${org_repo}"; then 125 if ! post_pull_request "${org_repo}" "${default_branch}"; then 126 return 1 127 fi 128 else 129 echo "Pushing ${branch} to ${org_repo} failed" 130 return 1 131 fi 132 fi 133} 134 135process_repo ${target_repo} 136