doc: Clarify the release process for a first stable
[tor.git] / scripts / git / git-push-all.sh
blobe5c16e615f268cfb06783bc61eb89d7947ba73da
1 #!/usr/bin/env bash
3 SCRIPT_NAME=$(basename "$0")
5 function usage()
7 if [ "$TOR_PUSH_SAME" ]; then
8 CURRENT_PUSH_SAME="push"
9 else
10 CURRENT_PUSH_SAME="skip"
13 echo "$SCRIPT_NAME [-h] [-r <remote-name> [-t <test-branch-prefix>]] [-s]"
14 # The next line looks misaligned, but it lines up in the output
15 echo " [-- [-n] [--no-atomic] <git push options>]"
16 echo
17 echo " arguments:"
18 echo " -h: show this help text"
19 echo " -n: dry run mode"
20 echo " (default: run commands)"
21 echo " -r: push to remote-name, rather than the default upstream remote."
22 echo " (default: $DEFAULT_UPSTREAM_REMOTE, current: $UPSTREAM_REMOTE)"
23 echo " -t: test branch mode: push test branches to remote-name. Pushes"
24 echo " branches prefix_035, prefix_040, ... , prefix_main."
25 echo " (default: push maint-*, release-*, and main)"
26 echo " -s: push branches whose tips match upstream maint, release, or"
27 echo " main branches. The default is to skip these branches,"
28 echo " because they do not contain any new code. Use -s to test for"
29 echo " CI environment failures, using code that previously passed CI."
30 echo " (default: skip; current: $CURRENT_PUSH_SAME matching branches)"
31 echo " --: pass further arguments to git push."
32 echo " All unrecognised arguments are passed to git push, but complex"
33 echo " arguments before -- may be mangled by getopt."
34 echo " (default: git push --atomic, current: $GIT_PUSH)"
35 echo
36 echo " env vars:"
37 echo " optional:"
38 echo " TOR_GIT_PUSH_PATH: change to this directory before pushing."
39 echo " (default: if \$TOR_FULL_GIT_PATH is set,"
40 echo " use \$TOR_FULL_GIT_PATH/\$TOR_MASTER;"
41 echo " Otherwise, use the current directory for pushes;"
42 echo " current: $TOR_GIT_PUSH_PATH)"
43 echo " TOR_FULL_GIT_PATH: where the git repository directories reside."
44 echo " We recommend using \$HOME/git/."
45 echo " (default: use the current directory for pushes;"
46 echo " current: $TOR_FULL_GIT_PATH)"
47 echo " TOR_MASTER: the name of the directory containing the tor.git clone"
48 echo " The primary tor git directory is \$GIT_PATH/\$TOR_MASTER"
49 echo " (default: tor; current: $TOR_MASTER_NAME)"
50 echo
51 echo " TOR_UPSTREAM_REMOTE_NAME: the default upstream remote."
52 echo " Overridden by -r."
53 echo " (default: upstream; current: $UPSTREAM_REMOTE)"
54 echo " TOR_GIT_PUSH: the git push command and default arguments."
55 echo " Overridden by <git push options> after --."
56 echo " (default: git push --atomic; current: $GIT_PUSH)"
57 echo " TOR_PUSH_SAME: push branches whose tips match upstream maint,"
58 echo " release, or main branches. Inverted by -s."
59 echo " (default: skip; current: $CURRENT_PUSH_SAME matching branches)"
60 echo " TOR_PUSH_DELAY: pushes the main and maint branches separately,"
61 echo " so that CI runs in a sensible order."
62 echo " (default: push all branches immediately; current: $PUSH_DELAY)"
63 echo " we recommend that you set these env vars in your ~/.profile"
66 set -e
68 #################
69 # Configuration #
70 #################
72 # Don't change this configuration - set the env vars in your .profile
74 # The primary tor git repository directory from which all the worktree have
75 # been created.
76 TOR_MASTER_NAME=${TOR_MASTER_NAME:-"tor"}
77 # Which directory do we push from?
78 if [ "$TOR_FULL_GIT_PATH" ]; then
79 TOR_GIT_PUSH_PATH=${TOR_GIT_PUSH_PATH:-"$TOR_FULL_GIT_PATH/$TOR_MASTER_NAME"}
81 # git push command and default arguments
82 GIT_PUSH=${TOR_GIT_PUSH:-"git push --atomic"}
83 # The upstream remote which git.torproject.org/tor.git points to.
84 DEFAULT_UPSTREAM_REMOTE=${TOR_UPSTREAM_REMOTE_NAME:-"upstream"}
85 # Push to a different upstream remote using -r <remote-name>
86 UPSTREAM_REMOTE=${DEFAULT_UPSTREAM_REMOTE}
87 # Add a delay between pushes, so CI runs on the most important branches first
88 PUSH_DELAY=${TOR_PUSH_DELAY:-0}
89 # Push (1) or skip (0) test branches that are the same as an upstream
90 # maint/main branch. Push if you are testing that the CI environment still
91 # works on old code, skip if you are testing new code in the branch.
92 # Default: skip unchanged branches.
93 # Inverted by the -s option.
94 PUSH_SAME=${TOR_PUSH_SAME:-0}
96 #######################
97 # Argument processing #
98 #######################
100 # Controlled by the -t <test-branch-prefix> option. The test branch prefix
101 # option makes git-merge-forward.sh create new test branches:
102 # <tbp>_035, <tbp>_040, ... , <tbp>_main, and merge each branch forward into
103 # the next one.
104 TEST_BRANCH_PREFIX=
106 while getopts ":hr:st:" opt; do
107 case "$opt" in
108 h) usage
109 exit 0
111 r) UPSTREAM_REMOTE="$OPTARG"
112 echo " *** PUSHING TO REMOTE: ${UPSTREAM_REMOTE} ***"
113 shift
114 shift
115 OPTIND=$((OPTIND - 2))
117 s) PUSH_SAME=$((! PUSH_SAME))
118 if [ "$PUSH_SAME" -eq 0 ]; then
119 echo " *** SKIPPING UNCHANGED TEST BRANCHES ***"
120 else
121 echo " *** PUSHING UNCHANGED TEST BRANCHES ***"
123 shift
124 OPTIND=$((OPTIND - 1))
126 t) TEST_BRANCH_PREFIX="$OPTARG"
127 echo " *** PUSHING TEST BRANCHES: ${TEST_BRANCH_PREFIX}_nnn ***"
128 shift
129 shift
130 OPTIND=$((OPTIND - 2))
133 # Make git push handle the option
134 # This might mangle options with spaces, use -- for complex options
135 GIT_PUSH="$GIT_PUSH $1"
136 shift
137 OPTIND=$((OPTIND - 1))
139 esac
140 done
142 # getopts doesn't allow "-" as an option character,
143 # so we have to handle -- manually
144 if [ "$1" = "--" ]; then
145 shift
148 if [ "$TEST_BRANCH_PREFIX" ]; then
149 if [ "$UPSTREAM_REMOTE" = "$DEFAULT_UPSTREAM_REMOTE" ]; then
150 echo "Pushing test branches ${TEST_BRANCH_PREFIX}_nnn to " \
151 "the default remote $DEFAULT_UPSTREAM_REMOTE is not allowed."
152 echo
153 usage
154 exit 1
158 if [ "$TOR_GIT_PUSH_PATH" ]; then
159 echo "Changing to $TOR_GIT_PUSH_PATH before pushing"
160 cd "$TOR_GIT_PUSH_PATH"
161 else
162 echo "Pushing from the current directory"
165 echo "Calling $GIT_PUSH" "$@" "<branches>"
167 ################################
168 # Git upstream remote branches #
169 ################################
171 set -e
172 DEFAULT_UPSTREAM_BRANCHES=
173 if [ "$DEFAULT_UPSTREAM_REMOTE" != "$UPSTREAM_REMOTE" ]; then
174 for br in $(git-list-tor-branches.sh -l); do
175 DEFAULT_UPSTREAM_BRANCHES="${DEFAULT_UPSTREAM_BRANCHES} ${DEFAULT_UPSTREAM_REMOTE}/${br}"
176 done
179 UPSTREAM_BRANCHES=
180 for br in $(git-list-tor-branches.sh -l); do
181 UPSTREAM_BRANCHES="${UPSTREAM_BRANCHES} ${UPSTREAM_REMOTE}/${br}"
182 done
184 ########################
185 # Git branches to push #
186 ########################
188 if [ -z "$TEST_BRANCH_PREFIX" ]; then
190 # maint/release push mode: push all branches.
192 # List of branches to push. Ordering is not important.
193 PUSH_BRANCHES="$(git-list-tor-branches.sh -l)"
194 else
196 # Test branch push mode: push test branches, based on each maint branch.
198 # List of branches to push. Ordering is not important.
199 PUSH_BRANCHES=""
200 for suffix in $(git-list-tor-branches.sh -s -R); do
201 PUSH_BRANCHES="${PUSH_BRANCHES} ${TEST_BRANCH_PREFIX}${suffix}"
202 done
205 set +e
207 ###############
208 # Entry point #
209 ###############
211 if [ "$TEST_BRANCH_PREFIX" ]; then
212 # Skip the test branches that are the same as the default or current
213 # upstream branches (they have already been tested)
214 UPSTREAM_SKIP_SAME_AS="$UPSTREAM_BRANCHES $DEFAULT_UPSTREAM_BRANCHES"
215 else
216 # Skip the local maint-*, release-*, main branches that are the same as the
217 # current upstream branches, but ignore the default upstream
218 # (we want to update a non-default remote, even if it matches the default)
219 UPSTREAM_SKIP_SAME_AS="$UPSTREAM_BRANCHES"
222 # Skip branches that match the relevant upstream(s)
223 if [ "$PUSH_SAME" -eq 0 ]; then
224 NEW_PUSH_BRANCHES=
225 for b in $PUSH_BRANCHES; do
226 PUSH_COMMIT=$(git rev-parse "$b")
227 SKIP_UPSTREAM=
228 for u in $UPSTREAM_SKIP_SAME_AS; do
229 # Skip the branch check on error
230 UPSTREAM_COMMIT=$(git rev-parse "$u" 2>/dev/null) || continue
231 if [ "$PUSH_COMMIT" = "$UPSTREAM_COMMIT" ]; then
232 SKIP_UPSTREAM="$u"
234 done
235 if [ "$SKIP_UPSTREAM" ]; then
236 printf "Skipping unchanged: %s matching remote: %s\\n" \
237 "$b" "$SKIP_UPSTREAM"
238 else
239 if [ "$NEW_PUSH_BRANCHES" ]; then
240 NEW_PUSH_BRANCHES="${NEW_PUSH_BRANCHES} ${b}"
241 else
242 NEW_PUSH_BRANCHES="${b}"
245 done
246 PUSH_BRANCHES=${NEW_PUSH_BRANCHES}
249 if [ ! "$PUSH_BRANCHES" ]; then
250 echo "No branches to push!"
251 # We expect the rest of the script to run without errors, even if there
252 # are no branches
255 if [ "$PUSH_DELAY" -le 0 ]; then
256 echo "Pushing $PUSH_BRANCHES"
257 # We know that there are no spaces in any branch within $PUSH_BRANCHES, so
258 # it is safe to use it unquoted. (This also applies to the other shellcheck
259 # exceptions below.)
261 # Push all the branches at the same time
262 # shellcheck disable=SC2086
263 $GIT_PUSH "$@" "$UPSTREAM_REMOTE" $PUSH_BRANCHES
264 else
265 # Push the branches in optimal CI order, with a delay between each push
266 PUSH_BRANCHES=$(echo "$PUSH_BRANCHES" | tr " " "\\n" | sort -V)
267 MASTER_BRANCH=$(echo "$PUSH_BRANCHES" | tr " " "\\n" | grep main$) \
268 || true # Skipped main branch
269 if [ -z "$TEST_BRANCH_PREFIX" ]; then
270 MAINT_BRANCHES=$(echo "$PUSH_BRANCHES" | tr " " "\\n" | grep maint) \
271 || true # Skipped all maint branches
272 RELEASE_BRANCHES=$(echo "$PUSH_BRANCHES" | tr " " "\\n" | grep release | \
273 tr "\\n" " ") || true # Skipped all release branches
274 else
275 # Actually test branches based on maint branches
276 MAINT_BRANCHES=$(echo "$PUSH_BRANCHES" | tr " " "\\n" | grep -v main$) \
277 || true # Skipped all maint test branches
278 # No release branches
279 RELEASE_BRANCHES=
281 if [ "$MASTER_BRANCH" ] || [ "$MAINT_BRANCHES" ] \
282 || [ "$RELEASE_BRANCHES" ]; then
283 printf "Pushing with %ss delays, so CI runs in this order:\\n" \
284 "$PUSH_DELAY"
285 if [ "$MASTER_BRANCH" ]; then
286 printf "%s\\n" "$MASTER_BRANCH"
288 if [ "$MAINT_BRANCHES" ]; then
289 printf "%s\\n" "$MAINT_BRANCHES"
291 if [ "$RELEASE_BRANCHES" ]; then
292 printf "%s\\n" "$RELEASE_BRANCHES"
295 # shellcheck disable=SC2086
296 for b in $MASTER_BRANCH $MAINT_BRANCHES; do
297 $GIT_PUSH "$@" "$UPSTREAM_REMOTE" "$b"
298 # If we are pushing more than one branch, delay. In the unlikely scenario
299 # where we are pushing maint branches without the main branch, or maint
300 # without release, there may be an extra delay
301 if [ "$MAINT_BRANCHES" ] || [ "$RELEASE_BRANCHES" ]; then
302 sleep "$PUSH_DELAY"
304 done
305 if [ "$RELEASE_BRANCHES" ]; then
306 # shellcheck disable=SC2086
307 $GIT_PUSH "$@" "$UPSTREAM_REMOTE" $RELEASE_BRANCHES