git-push-all.sh 8.0 KB

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