/ util / scripts / update_submodules
update_submodules
  1  #!/usr/bin/env bash
  2  #
  3  # SPDX-License-Identifier: GPL-2.0-only
  4  
  5  # Description:
  6  # Check all submodules for updates.  If there are more than a minimum
  7  # number of changes, create a commit to update the submodule to the
  8  # new version.
  9  
 10  set -eu -o pipefail
 11  
 12  VERSION="1.01"
 13  PROGRAM=$0
 14  PROGNAME="$(basename "${PROGRAM}")"
 15  
 16  export LANG=C
 17  export LC_ALL=C
 18  export TZ=UTC0
 19  
 20  min_commits=10
 21  TOP=${PWD}
 22  SUBMODULES_WITH_UPDATES=0
 23  submodule_dirs=()
 24  skip_sync=""
 25  max_commits_to_list=65
 26  
 27  show_version() {
 28  	echo "${PROGNAME} version ${VERSION}"
 29  	echo
 30  }
 31  
 32  usage() {
 33  	echo "Usage: ${PROGNAME} [options]"
 34  	echo
 35  	echo "Options:"
 36  	echo " -c | --changes <#>     Specify the minimum number of changes to update a repo"
 37  	echo " -h | --help            Print usage and exit"
 38  	echo " -R | --repo <dir>      Specify a single repo directory to update"
 39  	echo " -s | --skipsync        Assume that repos are already synced"
 40  	echo " -V | --version         Print the version and exit"
 41  	echo
 42  }
 43  
 44  get_args() {
 45  	args=$(getopt -l changes:,help,repo:,skipsync,version -o c:hR:sV -- "$@")
 46  	getopt_ret=$?
 47  	eval set -- "${args}"
 48  
 49  	if [ ${getopt_ret} != 0 ]; then
 50  		usage
 51  		exit 1
 52  	fi
 53  
 54  	while true; do
 55  		local opt
 56  		opt="$1"
 57  		shift
 58  		case "${opt}" in
 59  		-c | --changes)
 60  			min_commits="${1}"
 61  			shift
 62  			;;
 63  		-h | --help)
 64  			usage
 65  			exit 0
 66  			;;
 67  		-R | --repo)
 68  			submodule_dirs=("$(readlink -f "${1}")")
 69  			shift
 70  			if [[ ! -d "${submodule_dirs[0]}" ]]; then
 71  				echo "Error: ${submodule_dirs[0]} is not valid."
 72  				usage
 73  				exit 1
 74  			fi
 75  			;;
 76  		-s | --skipsync)
 77  			skip_sync=1
 78  			;;
 79  		-V | --version)
 80  			exit 0
 81  			;;
 82  		*)
 83  			break
 84  			;;
 85  		esac
 86  	done
 87  }
 88  
 89  
 90  main() {
 91  	show_version
 92  	get_args "$@"
 93  
 94  	if (( ${#submodule_dirs[@]} == 0 )); then
 95  		readarray -t submodule_dirs < <(git submodule foreach pwd | grep -v "Entering")
 96  	fi
 97  
 98  	for submodule in "${submodule_dirs[@]}"; do
 99  		echo "Checking submodule ${submodule}"
100  		if ! cd "$submodule"; then
101   			echo "Error: could not cd to $submodule"
102  			exit 1
103  		fi
104  
105  		initial_commit_id="$(git log --pretty='%h' -n 1 --abbrev=12)"
106  		initial_commit_description="$(git log --pretty='%ci - (%s)' -n 1)"
107  		if [[ ${skip_sync} != "1" ]]; then
108  			git fetch 2>/dev/null
109  		fi
110  
111  		declare -a branches=("origin/main" "origin/master" "origin/trunk")
112  		for branch in "${branches[@]}"; do
113  			if git branch -a | grep "${branch}" > /dev/null; then
114  				branch_name="${branch}"
115  				break
116  			fi
117  		done
118  
119  		updated_commit_id="$(git log --pretty='%h' -n 1 --abbrev=12 "${branch_name}" -- )"
120  		updated_commit_description="$(git log --pretty='%ci - (%s)' -n 1 "${updated_commit_id}")"
121  		if [ "${initial_commit_id}" = "${updated_commit_id}" ]; then
122  			echo "No updates for ${submodule}"
123  			continue
124  		fi
125  		SUBMODULES_WITH_UPDATES+=1
126  		update_log="$(git log --oneline --abbrev=12 "${initial_commit_id}..${updated_commit_id}")"
127  		update_count="$(echo "${update_log}" | wc -l)"
128  		if [[ "${update_count}" -gt "${max_commits_to_list}" ]]; then
129  			update_log=""
130  			new_commit_terminator="."
131  		else
132  			new_commit_terminator=":"
133  		fi
134  		echo "${update_count} new commits for ${submodule}"
135  		if [ "${update_count}" -ge "${min_commits}" ]; then
136  			echo "Creating commit to update ${submodule##*/} submodule"
137  			git checkout "${updated_commit_id}" > /dev/null 2>&1
138  			cd "${TOP}" || exit 1
139  			git add "${submodule}" > /dev/null 2>&1 || exit 1
140  			git commit -s -F- > /dev/null 2>&1 <<-EOF
141  	Update ${submodule##*/} submodule to upstream ${branch##*/}
142  
143  	Updating from commit id ${initial_commit_id}:
144  	$initial_commit_description
145  
146  	to commit id ${updated_commit_id}:
147  	${updated_commit_description}
148  
149  	This brings in ${update_count} new commits${new_commit_terminator}
150  	${update_log}
151  	EOF
152  		fi
153  	done
154  
155  	if [ "${SUBMODULES_WITH_UPDATES}" = "0" ]; then
156  		echo "No submodules with any updates."
157  	fi
158  }
159  
160  main "$@"