Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/bin/sh
- # This script will:
- # - list submodules inside a parent repository supplied on $1
- # - check whether they are marked as changed while ignoring dirty files
- # - verify that there are no other staged changes before proceeding
- # - send emails to the local user at the local hostname (-f) using the local
- # user also as the sender. It will send emails for: commit error,
- # staged changes existing, and success. It will not send emails for other
- # program errors. If you use this script from cron, then all other error
- # output will be sent to you by cron.
- # - the program will output some progress information on stdout; but will not
- # do so if the script is not run interactively.
- # This script is verified to work with: bash and busybox ash.
- # This program is called:
- # automatic parent commits
- unset int
- [ -t 0 ] && int=yes
- username=$(id -nu)
- hostname=$(hostname -f)
- email="$username@$hostname"
- medium_minus_date="commit %H%nAuthor: %an <%ae>%n%n%w(0,4,4)%B"
- [ -z "$1" ] && {
- echo "Give a git that has submodules as parameter" >&2
- exit 255
- }
- cd "$1" && {
- repository=$(readlink -f "$(pwd)")
- } || {
- echo "Directory $repository does not exist or is not accessable" >&2
- exit 1
- }
- [ -d .git ] || {
- echo "This is not a git repository: $repository" >&2
- exit 1
- }
- # get-url was not implemented in older git versions
- repo_name=$(git remote show -n origin | grep "Fetch URL" | sed "s@.*/\(.*\).git@\1@")
- # We shall first get the list of submodules using:
- submodules=$(git submodule -q foreach 'echo $path')
- [ -t 0 ] && { echo "List of submodules:"; echo "$submodules" | sed "s/.*/ &/"; echo; }
- # Then we shall hopefully find the list of modified submodules using:
- out=$(git status --porcelain --ignore-submodules=dirty) || {
- echo "Git status gave an error. Is this a git repository?" >&2
- exit 1
- }
- list=$(printf "%s\n" "$out" | sed "s/.*/#&/" | while read a; do
- # Spaces as meaningful characters is not easy in shell code.
- c=$(echo "$a" | sed "s/#.. //")
- b=${a% $c}
- b=${b#\#}
- # This first part filters on subrepository names.
- if echo "$submodules" | grep -q "^$c$"; then
- printf "%-2s %s\n" "$b" "$c"
- fi
- # Then we filter on an "M" in the second column.
- done | grep "^.M" | sed "s/.. //" )
- [ -t 0 ] && { echo "Submodules that are modified:"; echo "$list" | sed "s/.*/ &/"; echo; }
- # Then we shall go on.
- # I used to use the human readable version but it didn't tell me whether something was a submodule
- # when it already had the submodule staged for commit....:
- # out=$(echo "$out" | grep "^# modified:.*(.*new commits.*)$" | sed "s/.*: *\([^ ].*\) (.*)$/\1/")
- [ -z "$list" ] || {
- # Now we check whether the index does not contain staged changes:
- git status --porcelain --ignore-submodules=dirty | grep -q "^[MADRC]." && {
- # And we send an email if they are staged:
- echo "From: $email
- To: $email
- Subject: Repo $repo_name already contains staged changes
- There are sub-modules that have changes to be committed to the parent repo $repo_name but the index is not clean; there are staged changes:
- $(git status --ignore-submodules=dirty | sed -n -e "/^# Changes to be committed/,/^# [^ ]/p" | sed '$d')" | /usr/sbin/sendmail -t
- [ -t 0 ] && echo "Sent staged changes preventing operation mail to $email"
- # And we exit. Stash -u would take care of those staged things but unfortunately I don't think it is very
- # safe to do so.
- # I can't tell if I can ever lock a repository and files might also be open in the working tree that then
- # gets swapped around back and forth.
- # I would have to unstage things and then restage them back. That's easy enough but still runs the potential
- # risk of interfering with a user.
- # What I do needs to be atomic etc.
- exit 1
- }
- # Let's first determine the date to use for our commit message:
- # The date is slightly influenced by the locale (the %a term means like Wed)
- # This string results in "Wed 31-10-2017 22:00". I didn't like my own locale
- # (en_US becomes 10/31/2017 but nl_NL becomes 31-10-17 and locales also change dots into commas.
- # Very annoying. I hate that so much. Calculators don't take . input, only , input. So the thing
- # you're used to, typing 10.23 as a decimal number, suddenly doesn't work and the number becomes
- # 1023. That person who invented that deserves a proper hanging.
- date=$(date "+%a %d-%m-%Y %H:%M")
- # Anyway you can always change this around to your preference.
- # The list is now supplied with a here doc down below so that we can save the variables inside.
- unset error_repos errmsg changelist
- while read a; do
- git add "$a"
- currerr=$(git commit -m "Hourly repository update for submodule $a at $date" 2>&1 > /dev/null) && {
- changelist="$changelist$a
- "
- [ $int ] && echo "Successfully committed $a."
- true
- } || {
- error=$?
- error_repos="$error_repos$a
- "
- errmsg="$errmsg$currerr
- "
- [ $int ] && echo "Failed to commit $a."
- git reset -q "$a"
- }
- done << EOF
- $list
- EOF
- # Remove the extra \n I gave it:
- changelist=${changelist%?}
- error_repos=${error_repos%?}
- # If there were errors at committing they are now collected in this error repo list.
- [ -n "$error_repos" ] && {
- # start and error commits:
- first="From: $email
- To: $email
- Subject: Commits contain errors @ auto-update for $repo_name
- Commits that gave errors:
- $(echo -n "$error_repos" | sed "s/.*/- &/")"
- # any successful commits
- if [ -n "$changelist" ]; then
- first="$first
- Commits that succeeded:
- $(echo -n "$changelist" | sed "s/.*/- &/")"
- fi
- # the full message
- first="$first
- Error messages:
- $(echo -n "$errmsg" | sed "s/.*/ &/")"
- echo "$first" | /usr/sbin/sendmail -t
- [ -t 0 ] && echo "Sent error mail to $email"
- exit 1
- }
- # If not, then we proceed with a regular commit message as there MUST be successful commits now:
- count=$(echo "$changelist" | wc -l)
- if [ "$count" -gt 1 ]; then m=s; fi
- if [ "$count" -eq 1 ]; then
- echo "From: $email
- To: $email
- Subject: Updated parent for sub-module $repo_name/$changelist
- The repository $repo_name had its reference to submodule $changelist updated to its latest commit:
- $(cd $changelist; git log -1 --format="$medium_minus_date" | sed "s/.*/ &/")" | /usr/sbin/sendmail -t
- else
- { echo "From: $email
- To: $email
- Subject: Updated parent $repo_name for $count submodule repositories
- "
- while read r; do
- echo "The repository $repo_name had its reference to submodule $r updated to its latest commit:
- $(cd $r; git log -1 --format="$medium_minus_date" | sed "s/.*/ &/")
- "
- done << EOF
- $changelist
- EOF
- } | /usr/sbin/sendmail -t
- fi
- [ -t 0 ] && echo "Sent commit mail to $email"
- true
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement