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 10set -eu -o pipefail 11 12VERSION="1.01" 13PROGRAM=$0 14PROGNAME="$(basename "${PROGRAM}")" 15 16export LANG=C 17export LC_ALL=C 18export TZ=UTC0 19 20min_commits=10 21TOP=${PWD} 22SUBMODULES_WITH_UPDATES=0 23submodule_dirs=() 24skip_sync="" 25max_commits_to_list=65 26 27show_version() { 28 echo "${PROGNAME} version ${VERSION}" 29 echo 30} 31 32usage() { 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 44get_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 90main() { 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)" 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 "${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 "${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 160main "$@" 161