mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-12-11 05:03:34 +01:00
c80694decc
Hopefully, these explanations make it easier to get the next branch transition right. Part of 32772.
331 lines
11 KiB
Bash
Executable File
331 lines
11 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
SCRIPT_NAME=$(basename "$0")
|
|
|
|
function usage()
|
|
{
|
|
if [ "$TOR_PUSH_SAME" ]; then
|
|
CURRENT_PUSH_SAME="push"
|
|
else
|
|
CURRENT_PUSH_SAME="skip"
|
|
fi
|
|
|
|
echo "$SCRIPT_NAME [-h] [-r <remote-name> [-t <test-branch-prefix>]] [-s]"
|
|
# The next line looks misaligned, but it lines up in the output
|
|
echo " [-- [-n] [--no-atomic] <git push options>]"
|
|
echo
|
|
echo " arguments:"
|
|
echo " -h: show this help text"
|
|
echo " -n: dry run mode"
|
|
echo " (default: run commands)"
|
|
echo " -r: push to remote-name, rather than the default upstream remote."
|
|
echo " (default: $DEFAULT_UPSTREAM_REMOTE, current: $UPSTREAM_REMOTE)"
|
|
echo " -t: test branch mode: push test branches to remote-name. Pushes"
|
|
echo " branches prefix_035, prefix_040, ... , prefix_master."
|
|
echo " (default: push maint-*, release-*, and master)"
|
|
echo " -s: push branches whose tips match upstream maint, release, or"
|
|
echo " master branches. The default is to skip these branches,"
|
|
echo " because they do not contain any new code. Use -s to test for"
|
|
echo " CI environment failures, using code that previously passed CI."
|
|
echo " (default: skip; current: $CURRENT_PUSH_SAME matching branches)"
|
|
echo " --: pass further arguments to git push."
|
|
echo " All unrecognised arguments are passed to git push, but complex"
|
|
echo " arguments before -- may be mangled by getopt."
|
|
echo " (default: git push --atomic, current: $GIT_PUSH)"
|
|
echo
|
|
echo " env vars:"
|
|
echo " optional:"
|
|
echo " TOR_GIT_PUSH_PATH: change to this directory before pushing."
|
|
echo " (default: if \$TOR_FULL_GIT_PATH is set,"
|
|
echo " use \$TOR_FULL_GIT_PATH/\$TOR_MASTER;"
|
|
echo " Otherwise, use the current directory for pushes;"
|
|
echo " current: $TOR_GIT_PUSH_PATH)"
|
|
echo " TOR_FULL_GIT_PATH: where the git repository directories reside."
|
|
echo " We recommend using \$HOME/git/."
|
|
echo " (default: use the current directory for pushes;"
|
|
echo " current: $TOR_FULL_GIT_PATH)"
|
|
echo " TOR_MASTER: the name of the directory containing the tor.git clone"
|
|
echo " The tor master git directory is \$GIT_PATH/\$TOR_MASTER"
|
|
echo " (default: tor; current: $TOR_MASTER_NAME)"
|
|
echo
|
|
echo " TOR_UPSTREAM_REMOTE_NAME: the default upstream remote."
|
|
echo " Overridden by -r."
|
|
echo " (default: upstream; current: $UPSTREAM_REMOTE)"
|
|
echo " TOR_GIT_PUSH: the git push command and default arguments."
|
|
echo " Overridden by <git push options> after --."
|
|
echo " (default: git push --atomic; current: $GIT_PUSH)"
|
|
echo " TOR_PUSH_SAME: push branches whose tips match upstream maint,"
|
|
echo " release, or master branches. Inverted by -s."
|
|
echo " (default: skip; current: $CURRENT_PUSH_SAME matching branches)"
|
|
echo " TOR_PUSH_DELAY: pushes the master and maint branches separately,"
|
|
echo " so that CI runs in a sensible order."
|
|
echo " (default: push all branches immediately; current: $PUSH_DELAY)"
|
|
echo " we recommend that you set these env vars in your ~/.profile"
|
|
}
|
|
|
|
set -e
|
|
|
|
#################
|
|
# Configuration #
|
|
#################
|
|
|
|
# Don't change this configuration - set the env vars in your .profile
|
|
#
|
|
# The tor master git repository directory from which all the worktree have
|
|
# been created.
|
|
TOR_MASTER_NAME=${TOR_MASTER_NAME:-"tor"}
|
|
# Which directory do we push from?
|
|
if [ "$TOR_FULL_GIT_PATH" ]; then
|
|
TOR_GIT_PUSH_PATH=${TOR_GIT_PUSH_PATH:-"$TOR_FULL_GIT_PATH/$TOR_MASTER_NAME"}
|
|
fi
|
|
# git push command and default arguments
|
|
GIT_PUSH=${TOR_GIT_PUSH:-"git push --atomic"}
|
|
# The upstream remote which git.torproject.org/tor.git points to.
|
|
DEFAULT_UPSTREAM_REMOTE=${TOR_UPSTREAM_REMOTE_NAME:-"upstream"}
|
|
# Push to a different upstream remote using -r <remote-name>
|
|
UPSTREAM_REMOTE=${DEFAULT_UPSTREAM_REMOTE}
|
|
# Add a delay between pushes, so CI runs on the most important branches first
|
|
PUSH_DELAY=${TOR_PUSH_DELAY:-0}
|
|
# Push (1) or skip (0) test branches that are the same as an upstream
|
|
# maint/master branch. Push if you are testing that the CI environment still
|
|
# works on old code, skip if you are testing new code in the branch.
|
|
# Default: skip unchanged branches.
|
|
# Inverted by the -s option.
|
|
PUSH_SAME=${TOR_PUSH_SAME:-0}
|
|
|
|
#######################
|
|
# Argument processing #
|
|
#######################
|
|
|
|
# Controlled by the -t <test-branch-prefix> option. The test branch prefix
|
|
# option makes git-merge-forward.sh create new test branches:
|
|
# <tbp>_035, <tbp>_040, ... , <tbp>_master, and merge each branch forward into
|
|
# the next one.
|
|
TEST_BRANCH_PREFIX=
|
|
|
|
while getopts ":hr:st:" opt; do
|
|
case "$opt" in
|
|
h) usage
|
|
exit 0
|
|
;;
|
|
r) UPSTREAM_REMOTE="$OPTARG"
|
|
echo " *** PUSHING TO REMOTE: ${UPSTREAM_REMOTE} ***"
|
|
shift
|
|
shift
|
|
OPTIND=$((OPTIND - 2))
|
|
;;
|
|
s) PUSH_SAME=$((! PUSH_SAME))
|
|
if [ "$PUSH_SAME" -eq 0 ]; then
|
|
echo " *** SKIPPING UNCHANGED TEST BRANCHES ***"
|
|
else
|
|
echo " *** PUSHING UNCHANGED TEST BRANCHES ***"
|
|
fi
|
|
shift
|
|
OPTIND=$((OPTIND - 1))
|
|
;;
|
|
t) TEST_BRANCH_PREFIX="$OPTARG"
|
|
echo " *** PUSHING TEST BRANCHES: ${TEST_BRANCH_PREFIX}_nnn ***"
|
|
shift
|
|
shift
|
|
OPTIND=$((OPTIND - 2))
|
|
;;
|
|
*)
|
|
# Make git push handle the option
|
|
# This might mangle options with spaces, use -- for complex options
|
|
GIT_PUSH="$GIT_PUSH $1"
|
|
shift
|
|
OPTIND=$((OPTIND - 1))
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# getopts doesn't allow "-" as an option character,
|
|
# so we have to handle -- manually
|
|
if [ "$1" = "--" ]; then
|
|
shift
|
|
fi
|
|
|
|
if [ "$TEST_BRANCH_PREFIX" ]; then
|
|
if [ "$UPSTREAM_REMOTE" = "$DEFAULT_UPSTREAM_REMOTE" ]; then
|
|
echo "Pushing test branches ${TEST_BRANCH_PREFIX}_nnn to " \
|
|
"the default remote $DEFAULT_UPSTREAM_REMOTE is not allowed."
|
|
echo
|
|
usage
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
if [ "$TOR_GIT_PUSH_PATH" ]; then
|
|
echo "Changing to $TOR_GIT_PUSH_PATH before pushing"
|
|
cd "$TOR_GIT_PUSH_PATH"
|
|
else
|
|
echo "Pushing from the current directory"
|
|
fi
|
|
|
|
echo "Calling $GIT_PUSH" "$@" "<branches>"
|
|
|
|
################################
|
|
# Git upstream remote branches #
|
|
################################
|
|
|
|
DEFAULT_UPSTREAM_BRANCHES=
|
|
if [ "$DEFAULT_UPSTREAM_REMOTE" != "$UPSTREAM_REMOTE" ]; then
|
|
DEFAULT_UPSTREAM_BRANCHES=$(echo \
|
|
"$DEFAULT_UPSTREAM_REMOTE"/master \
|
|
"$DEFAULT_UPSTREAM_REMOTE"/{release,maint}-0.4.2 \
|
|
"$DEFAULT_UPSTREAM_REMOTE"/{release,maint}-0.4.1 \
|
|
"$DEFAULT_UPSTREAM_REMOTE"/{release,maint}-0.4.0 \
|
|
"$DEFAULT_UPSTREAM_REMOTE"/{release,maint}-0.3.5 \
|
|
)
|
|
fi
|
|
|
|
UPSTREAM_BRANCHES=$(echo \
|
|
"$UPSTREAM_REMOTE"/master \
|
|
"$UPSTREAM_REMOTE"/{release,maint}-0.4.2 \
|
|
"$UPSTREAM_REMOTE"/{release,maint}-0.4.1 \
|
|
"$UPSTREAM_REMOTE"/{release,maint}-0.4.0 \
|
|
"$UPSTREAM_REMOTE"/{release,maint}-0.3.5 \
|
|
)
|
|
|
|
########################
|
|
# Git branches to push #
|
|
########################
|
|
|
|
PUSH_BRANCHES=$(echo \
|
|
master \
|
|
{release,maint}-0.4.2 \
|
|
{release,maint}-0.4.1 \
|
|
{release,maint}-0.4.0 \
|
|
{release,maint}-0.3.5 \
|
|
)
|
|
|
|
if [ -z "$TEST_BRANCH_PREFIX" ]; then
|
|
|
|
# maint/release push mode: push all branches.
|
|
#
|
|
# List of branches to push. Ordering is not important.
|
|
PUSH_BRANCHES=$(echo \
|
|
master \
|
|
{release,maint}-0.4.2 \
|
|
{release,maint}-0.4.1 \
|
|
{release,maint}-0.4.0 \
|
|
{release,maint}-0.3.5 \
|
|
)
|
|
else
|
|
|
|
# Test branch push mode: push test branches, based on each maint branch.
|
|
#
|
|
# List of branches to push. Ordering is not important.
|
|
PUSH_BRANCHES=" \
|
|
${TEST_BRANCH_PREFIX}_master \
|
|
${TEST_BRANCH_PREFIX}_042 \
|
|
${TEST_BRANCH_PREFIX}_041 \
|
|
${TEST_BRANCH_PREFIX}_040 \
|
|
${TEST_BRANCH_PREFIX}_035 \
|
|
"
|
|
fi
|
|
|
|
###############
|
|
# Entry point #
|
|
###############
|
|
|
|
if [ "$TEST_BRANCH_PREFIX" ]; then
|
|
# Skip the test branches that are the same as the default or current
|
|
# upstream branches (they have already been tested)
|
|
UPSTREAM_SKIP_SAME_AS="$UPSTREAM_BRANCHES $DEFAULT_UPSTREAM_BRANCHES"
|
|
else
|
|
# Skip the local maint-*, release-*, master branches that are the same as the
|
|
# current upstream branches, but ignore the default upstream
|
|
# (we want to update a non-default remote, even if it matches the default)
|
|
UPSTREAM_SKIP_SAME_AS="$UPSTREAM_BRANCHES"
|
|
fi
|
|
|
|
# Skip branches that match the relevant upstream(s)
|
|
if [ "$PUSH_SAME" -eq 0 ]; then
|
|
NEW_PUSH_BRANCHES=
|
|
for b in $PUSH_BRANCHES; do
|
|
PUSH_COMMIT=$(git rev-parse "$b")
|
|
SKIP_UPSTREAM=
|
|
for u in $UPSTREAM_SKIP_SAME_AS; do
|
|
# Skip the branch check on error
|
|
UPSTREAM_COMMIT=$(git rev-parse "$u" 2>/dev/null) || continue
|
|
if [ "$PUSH_COMMIT" = "$UPSTREAM_COMMIT" ]; then
|
|
SKIP_UPSTREAM="$u"
|
|
fi
|
|
done
|
|
if [ "$SKIP_UPSTREAM" ]; then
|
|
printf "Skipping unchanged: %s matching remote: %s\\n" \
|
|
"$b" "$SKIP_UPSTREAM"
|
|
else
|
|
if [ "$NEW_PUSH_BRANCHES" ]; then
|
|
NEW_PUSH_BRANCHES="${NEW_PUSH_BRANCHES} ${b}"
|
|
else
|
|
NEW_PUSH_BRANCHES="${b}"
|
|
fi
|
|
fi
|
|
done
|
|
PUSH_BRANCHES=${NEW_PUSH_BRANCHES}
|
|
fi
|
|
|
|
if [ ! "$PUSH_BRANCHES" ]; then
|
|
echo "No branches to push!"
|
|
# We expect the rest of the script to run without errors, even if there
|
|
# are no branches
|
|
fi
|
|
|
|
if [ "$PUSH_DELAY" -le 0 ]; then
|
|
echo "Pushing $PUSH_BRANCHES"
|
|
# We know that there are no spaces in any branch within $PUSH_BRANCHES, so
|
|
# it is safe to use it unquoted. (This also applies to the other shellcheck
|
|
# exceptions below.)
|
|
#
|
|
# Push all the branches at the same time
|
|
# shellcheck disable=SC2086
|
|
$GIT_PUSH "$@" "$UPSTREAM_REMOTE" $PUSH_BRANCHES
|
|
else
|
|
# Push the branches in optimal CI order, with a delay between each push
|
|
PUSH_BRANCHES=$(echo "$PUSH_BRANCHES" | tr " " "\\n" | sort -V)
|
|
MASTER_BRANCH=$(echo "$PUSH_BRANCHES" | tr " " "\\n" | grep master) \
|
|
|| true # Skipped master branch
|
|
if [ -z "$TEST_BRANCH_PREFIX" ]; then
|
|
MAINT_BRANCHES=$(echo "$PUSH_BRANCHES" | tr " " "\\n" | grep maint) \
|
|
|| true # Skipped all maint branches
|
|
RELEASE_BRANCHES=$(echo "$PUSH_BRANCHES" | tr " " "\\n" | grep release | \
|
|
tr "\\n" " ") || true # Skipped all release branches
|
|
else
|
|
# Actually test branches based on maint branches
|
|
MAINT_BRANCHES=$(echo "$PUSH_BRANCHES" | tr " " "\\n" | grep -v master) \
|
|
|| true # Skipped all maint test branches
|
|
# No release branches
|
|
RELEASE_BRANCHES=
|
|
fi
|
|
if [ "$MASTER_BRANCH" ] || [ "$MAINT_BRANCHES" ] \
|
|
|| [ "$RELEASE_BRANCHES" ]; then
|
|
printf "Pushing with %ss delays, so CI runs in this order:\\n" \
|
|
"$PUSH_DELAY"
|
|
if [ "$MASTER_BRANCH" ]; then
|
|
printf "%s\\n" "$MASTER_BRANCH"
|
|
fi
|
|
if [ "$MAINT_BRANCHES" ]; then
|
|
printf "%s\\n" "$MAINT_BRANCHES"
|
|
fi
|
|
if [ "$RELEASE_BRANCHES" ]; then
|
|
printf "%s\\n" "$RELEASE_BRANCHES"
|
|
fi
|
|
fi
|
|
# shellcheck disable=SC2086
|
|
for b in $MASTER_BRANCH $MAINT_BRANCHES; do
|
|
$GIT_PUSH "$@" "$UPSTREAM_REMOTE" "$b"
|
|
# If we are pushing more than one branch, delay.
|
|
# In the unlikely scenario where we are pushing maint without master,
|
|
# or maint without release, there may be an extra delay
|
|
if [ "$MAINT_BRANCHES" ] || [ "$RELEASE_BRANCHES" ]; then
|
|
sleep "$PUSH_DELAY"
|
|
fi
|
|
done
|
|
if [ "$RELEASE_BRANCHES" ]; then
|
|
# shellcheck disable=SC2086
|
|
$GIT_PUSH "$@" "$UPSTREAM_REMOTE" $RELEASE_BRANCHES
|
|
fi
|
|
fi
|