git-push-all.sh 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. #!/usr/bin/env bash
  2. SCRIPT_NAME=$(basename "$0")
  3. function usage()
  4. {
  5. if [ "$TOR_PUSH_SAME" ]; then
  6. CURRENT_PUSH_SAME="push"
  7. else
  8. CURRENT_PUSH_SAME="skip"
  9. fi
  10. echo "$SCRIPT_NAME [-h] [-r <remote-name> [-t <test-branch-prefix>]] [-s]"
  11. # The next line looks misaligned, but it lines up in the output
  12. echo " [-- [-n] [--no-atomic] <git push options>]"
  13. echo
  14. echo " arguments:"
  15. echo " -h: show this help text"
  16. echo " -n: dry run mode"
  17. echo " (default: run commands)"
  18. echo " -r: push to remote-name, rather than the default upstream remote."
  19. echo " (default: $DEFAULT_UPSTREAM_REMOTE, current: $UPSTREAM_REMOTE)"
  20. echo " -t: test branch mode: push test branches to remote-name. Pushes"
  21. echo " branches prefix_029, prefix_035, ... , prefix_master."
  22. echo " (default: push maint-*, release-*, and master)"
  23. echo " -s: push branches whose tips match upstream maint, release, or"
  24. echo " master branches. The default is to skip these branches,"
  25. echo " because they do not contain any new code. Use -s to test for"
  26. echo " CI environment failures, using code that previously passed CI."
  27. echo " (default: skip; current: $CURRENT_PUSH_SAME matching branches)"
  28. echo " --: pass further arguments to git push."
  29. echo " (default: git push --atomic, current: $GIT_PUSH)"
  30. echo
  31. echo " env vars:"
  32. echo " optional:"
  33. echo " TOR_GIT_PUSH_PATH: change to this directory before pushing."
  34. echo " (default: if \$TOR_FULL_GIT_PATH is set,"
  35. echo " use \$TOR_FULL_GIT_PATH/\$TOR_MASTER;"
  36. echo " Otherwise, use the current directory for pushes;"
  37. echo " current: $TOR_GIT_PUSH_PATH)"
  38. echo " TOR_FULL_GIT_PATH: where the git repository directories reside."
  39. echo " We recommend using \$HOME/git/."
  40. echo " (default: use the current directory for pushes;"
  41. echo " current: $TOR_FULL_GIT_PATH)"
  42. echo " TOR_MASTER: the name of the directory containing the tor.git clone"
  43. echo " The tor master git directory is \$GIT_PATH/\$TOR_MASTER"
  44. echo " (default: tor; current: $TOR_MASTER_NAME)"
  45. echo
  46. echo " TOR_UPSTREAM_REMOTE_NAME: the default upstream remote."
  47. echo " Overridden by -r."
  48. echo " (default: upstream; current: $UPSTREAM_REMOTE)"
  49. echo " TOR_GIT_PUSH: the git push command and default arguments."
  50. echo " Overridden by <git push options> after --."
  51. echo " (default: git push --atomic; current: $GIT_PUSH)"
  52. echo " TOR_PUSH_SAME: push branches whose tips match upstream maint,"
  53. echo " release, or master branches. Inverted by -s."
  54. echo " (default: skip; current: $CURRENT_PUSH_SAME matching branches)"
  55. echo " TOR_PUSH_DELAY: pushes the master and maint branches separately,"
  56. echo " so that CI runs in a sensible order."
  57. echo " (default: push all branches immediately; current: $PUSH_DELAY)"
  58. echo " we recommend that you set these env vars in your ~/.profile"
  59. }
  60. set -e
  61. #################
  62. # Configuration #
  63. #################
  64. # Don't change this configuration - set the env vars in your .profile
  65. #
  66. # The tor master git repository directory from which all the worktree have
  67. # been created.
  68. TOR_MASTER_NAME=${TOR_MASTER_NAME:-"tor"}
  69. # Which directory do we push from?
  70. if [ "$TOR_FULL_GIT_PATH" ]; then
  71. TOR_GIT_PUSH_PATH=${TOR_GIT_PUSH_PATH:-"$TOR_FULL_GIT_PATH/$TOR_MASTER_NAME"}
  72. fi
  73. # git push command and default arguments
  74. GIT_PUSH=${TOR_GIT_PUSH:-"git push --atomic"}
  75. # The upstream remote which git.torproject.org/tor.git points to.
  76. DEFAULT_UPSTREAM_REMOTE=${TOR_UPSTREAM_REMOTE_NAME:-"upstream"}
  77. # Push to a different upstream remote using -r <remote-name>
  78. UPSTREAM_REMOTE=${DEFAULT_UPSTREAM_REMOTE}
  79. # Add a delay between pushes, so CI runs on the most important branches first
  80. PUSH_DELAY=${TOR_PUSH_DELAY:-0}
  81. # Push (1) or skip (0) test branches that are the same as an upstream
  82. # maint/master branch. Push if you are testing that the CI environment still
  83. # works on old code, skip if you are testing new code in the branch.
  84. # Default: skip unchanged branches.
  85. # Inverted by the -s option.
  86. PUSH_SAME=${TOR_PUSH_SAME:-0}
  87. #######################
  88. # Argument processing #
  89. #######################
  90. # Controlled by the -t <test-branch-prefix> option. The test branch base
  91. # name option makes git-merge-forward.sh create new test branches:
  92. # <tbbn>_029, <tbbn>_035, ... , <tbbn>_master, and merge forward.
  93. TEST_BRANCH_PREFIX=
  94. while getopts ":hr:st:" opt; do
  95. case "$opt" in
  96. h) usage
  97. exit 0
  98. ;;
  99. r) UPSTREAM_REMOTE="$OPTARG"
  100. echo " *** PUSHING TO REMOTE: ${UPSTREAM_REMOTE} ***"
  101. shift
  102. shift
  103. OPTIND=$((OPTIND - 2))
  104. ;;
  105. s) PUSH_SAME=$((! PUSH_SAME))
  106. if [ "$PUSH_SAME" -eq 0 ]; then
  107. echo " *** SKIPPING UNCHANGED TEST BRANCHES ***"
  108. else
  109. echo " *** PUSHING UNCHANGED TEST BRANCHES ***"
  110. fi
  111. shift
  112. OPTIND=$((OPTIND - 1))
  113. ;;
  114. t) TEST_BRANCH_PREFIX="$OPTARG"
  115. echo " *** PUSHING TEST BRANCHES: ${TEST_BRANCH_PREFIX}_nnn ***"
  116. shift
  117. shift
  118. OPTIND=$((OPTIND - 2))
  119. ;;
  120. *)
  121. # Assume we're done with script arguments,
  122. # and git push will handle the option
  123. break
  124. ;;
  125. esac
  126. done
  127. # getopts doesn't allow "-" as an option character,
  128. # so we have to handle -- manually
  129. if [ "$1" = "--" ]; then
  130. shift
  131. fi
  132. if [ "$TEST_BRANCH_PREFIX" ]; then
  133. if [ "$UPSTREAM_REMOTE" = "$DEFAULT_UPSTREAM_REMOTE" ]; then
  134. echo "Pushing test branches ${TEST_BRANCH_PREFIX}_nnn to " \
  135. "the default remote $DEFAULT_UPSTREAM_REMOTE is not allowed."
  136. echo
  137. usage
  138. exit 1
  139. fi
  140. fi
  141. if [ "$TOR_GIT_PUSH_PATH" ]; then
  142. echo "Changing to $GIT_PUSH_PATH before pushing"
  143. cd "$TOR_GIT_PUSH_PATH"
  144. else
  145. echo "Pushing from the current directory"
  146. fi
  147. echo "Calling $GIT_PUSH" "$@" "<branches>"
  148. ################################
  149. # Git upstream remote branches #
  150. ################################
  151. DEFAULT_UPSTREAM_BRANCHES=
  152. if [ "$DEFAULT_UPSTREAM_REMOTE" != "$UPSTREAM_REMOTE" ]; then
  153. DEFAULT_UPSTREAM_BRANCHES=$(echo \
  154. "$DEFAULT_UPSTREAM_REMOTE"/master \
  155. "$DEFAULT_UPSTREAM_REMOTE"/{release,maint}-0.4.1 \
  156. "$DEFAULT_UPSTREAM_REMOTE"/{release,maint}-0.4.0 \
  157. "$DEFAULT_UPSTREAM_REMOTE"/{release,maint}-0.3.5 \
  158. "$DEFAULT_UPSTREAM_REMOTE"/{release,maint}-0.2.9 \
  159. )
  160. fi
  161. UPSTREAM_BRANCHES=$(echo \
  162. "$UPSTREAM_REMOTE"/master \
  163. "$UPSTREAM_REMOTE"/{release,maint}-0.4.1 \
  164. "$UPSTREAM_REMOTE"/{release,maint}-0.4.0 \
  165. "$UPSTREAM_REMOTE"/{release,maint}-0.3.5 \
  166. "$UPSTREAM_REMOTE"/{release,maint}-0.2.9 \
  167. )
  168. ########################
  169. # Git branches to push #
  170. ########################
  171. PUSH_BRANCHES=$(echo \
  172. master \
  173. {release,maint}-0.4.1 \
  174. {release,maint}-0.4.0 \
  175. {release,maint}-0.3.5 \
  176. {release,maint}-0.2.9 \
  177. )
  178. if [ -z "$TEST_BRANCH_PREFIX" ]; then
  179. # maint/release push mode
  180. #
  181. # List of branches to push. Ordering is not important.
  182. PUSH_BRANCHES=$(echo \
  183. master \
  184. {release,maint}-0.4.1 \
  185. {release,maint}-0.4.0 \
  186. {release,maint}-0.3.5 \
  187. {release,maint}-0.2.9 \
  188. )
  189. else
  190. # Test branch mode: merge to maint only, and create a new branch for 0.2.9
  191. #
  192. # List of branches to push. Ordering is not important.
  193. PUSH_BRANCHES=" \
  194. ${TEST_BRANCH_PREFIX}_master \
  195. ${TEST_BRANCH_PREFIX}_041 \
  196. ${TEST_BRANCH_PREFIX}_040 \
  197. ${TEST_BRANCH_PREFIX}_035 \
  198. ${TEST_BRANCH_PREFIX}_029 \
  199. "
  200. fi
  201. ###############
  202. # Entry point #
  203. ###############
  204. # Skip the test branches that are the same as the upstream branches
  205. if [ "$PUSH_SAME" -eq 0 ] && [ "$TEST_BRANCH_PREFIX" ]; then
  206. NEW_PUSH_BRANCHES=
  207. for b in $PUSH_BRANCHES; do
  208. PUSH_COMMIT=$(git rev-parse "$b")
  209. SKIP_UPSTREAM=
  210. for u in $DEFAULT_UPSTREAM_BRANCHES $UPSTREAM_BRANCHES; do
  211. UPSTREAM_COMMIT=$(git rev-parse "$u")
  212. if [ "$PUSH_COMMIT" = "$UPSTREAM_COMMIT" ]; then
  213. SKIP_UPSTREAM="$u"
  214. fi
  215. done
  216. if [ "$SKIP_UPSTREAM" ]; then
  217. printf "Skipping unchanged: %s remote: %s\\n" \
  218. "$b" "$SKIP_UPSTREAM"
  219. else
  220. if [ "$NEW_PUSH_BRANCHES" ]; then
  221. NEW_PUSH_BRANCHES="${NEW_PUSH_BRANCHES} ${b}"
  222. else
  223. NEW_PUSH_BRANCHES="${b}"
  224. fi
  225. fi
  226. done
  227. PUSH_BRANCHES=${NEW_PUSH_BRANCHES}
  228. fi
  229. if [ "$PUSH_DELAY" -le 0 ]; then
  230. echo "Pushing $PUSH_BRANCHES"
  231. # We know that there are no spaces in any branch within $PUSH_BRANCHES, so
  232. # it is safe to use it unquoted. (This also applies to the other shellcheck
  233. # exceptions below.)
  234. #
  235. # Push all the branches at the same time
  236. # shellcheck disable=SC2086
  237. $GIT_PUSH "$@" "$UPSTREAM_REMOTE" $PUSH_BRANCHES
  238. else
  239. # Push the branches in optimal CI order, with a delay between each push
  240. PUSH_BRANCHES=$(echo "$PUSH_BRANCHES" | tr " " "\\n" | sort -V)
  241. MASTER_BRANCH=$(echo "$PUSH_BRANCHES" | tr " " "\\n" | grep master)
  242. if [ -z "$TEST_BRANCH_PREFIX" ]; then
  243. MAINT_BRANCHES=$(echo "$PUSH_BRANCHES" | tr " " "\\n" | grep maint)
  244. RELEASE_BRANCHES=$(echo "$PUSH_BRANCHES" | tr " " "\\n" | grep release | \
  245. tr "\\n" " ")
  246. printf \
  247. "Pushing with %ss delays, so CI runs in this order:\\n%s\\n%s\\n%s\\n" \
  248. "$PUSH_DELAY" "$MASTER_BRANCH" "$MAINT_BRANCHES" "$RELEASE_BRANCHES"
  249. else
  250. # Actually test branches based on maint branches
  251. MAINT_BRANCHES=$(echo "$PUSH_BRANCHES" | tr " " "\\n" | grep -v master)
  252. printf "Pushing with %ss delays, so CI runs in this order:\\n%s\\n%s\\n" \
  253. "$PUSH_DELAY" "$MASTER_BRANCH" "$MAINT_BRANCHES"
  254. # No release branches
  255. RELEASE_BRANCHES=
  256. fi
  257. $GIT_PUSH "$@" "$UPSTREAM_REMOTE" "$MASTER_BRANCH"
  258. sleep "$PUSH_DELAY"
  259. # shellcheck disable=SC2086
  260. for b in $MAINT_BRANCHES; do
  261. $GIT_PUSH "$@" "$UPSTREAM_REMOTE" "$b"
  262. sleep "$PUSH_DELAY"
  263. done
  264. if [ "$RELEASE_BRANCHES" ]; then
  265. # shellcheck disable=SC2086
  266. $GIT_PUSH "$@" "$UPSTREAM_REMOTE" $RELEASE_BRANCHES
  267. fi
  268. fi