|
| 1 | +#!/usr/bin/env bash |
| 2 | + |
| 3 | +set -e |
| 4 | +if [ "$BOILERPLATE_SET_X" ]; then |
| 5 | + set -x |
| 6 | +fi |
| 7 | + |
| 8 | +REPO_ROOT=$(git rev-parse --show-toplevel) |
| 9 | +source $REPO_ROOT/boilerplate/_lib/common.sh |
| 10 | + |
| 11 | +tmpd=$(mktemp -d) |
| 12 | +trap "rm -fr $tmpd" EXIT |
| 13 | +git_status=$tmpd/git_status |
| 14 | +bp_log=$tmpd/bp_git_log |
| 15 | +bp_clone=$tmpd/bp_git_clone |
| 16 | +convention_status=$tmpd/convention_status |
| 17 | +commit_message=$tmpd/commit_msg |
| 18 | + |
| 19 | +# Variables to keep track of what's happening in this commit. Empty |
| 20 | +# means we're not doing whatever it is. |
| 21 | +#### |
| 22 | +# - Bootstrapping: bringing boilerplate into the repo for the first |
| 23 | +# time. Nonempty if bootstrapping. |
| 24 | +bootstrap= |
| 25 | +#### |
| 26 | +# - If we were already bootstrapped, and boilerplate-update brought in a |
| 27 | +# newer boilerplate commit, we'll put "{from_hash}...{to_hash}" here. |
| 28 | +# This should be mutually exclusive with `bootstrap`. |
| 29 | +bp_commit_change= |
| 30 | +#### |
| 31 | +# - Changes in conventions. This is a file containing one line per |
| 32 | +# convention indicating what was done in this commit with respect to |
| 33 | +# that convention: "Subscribe", "Update", or "No change". (TODO: |
| 34 | +# "Unsubscribe".) The file is only empty if update.cfg is |
| 35 | +# (substantively) empty. |
| 36 | +convention_statuses=$tmpd/convention_statuses |
| 37 | +>$convention_statuses |
| 38 | +#### |
| 39 | + |
| 40 | +git status --porcelain > $git_status |
| 41 | + |
| 42 | +# Bootstrapping includes adding the boilerplate-update target to the |
| 43 | +# Makefile and adding boilerplate/update and boilerplate/update.cfg. We |
| 44 | +# won't bother with the former. Since the latter are new files in a new |
| 45 | +# directory, `git status` will just show the `boilerplate/` directory as |
| 46 | +# untracked. |
| 47 | +if grep -q '^?? boilerplate/$' $git_status; then |
| 48 | + bootstrap=true |
| 49 | + |
| 50 | +# This wasn't a bootstrap. We can detect it was an update if the |
| 51 | +# last-boilerplate-commit file was changed. |
| 52 | +elif grep -q '^ M boilerplate/_data/last-boilerplate-commit$' $git_status; then |
| 53 | + # Produce a string of the form {old_hash}...{new_hash} |
| 54 | + bp_commit_change=$(git diff boilerplate/_data/last-boilerplate-commit | tail -2 | paste -d/ -s - | sed 's/[+-]//g; s,/,...,') |
| 55 | + # Handy URL showing the commits and deltas |
| 56 | + bp_compare_url="https://github.com/openshift/boilerplate/compare/$bp_commit_change" |
| 57 | + # Generate the commit history for this range. This will go in the commit message. |
| 58 | + ( |
| 59 | + if [[ -z "${BOILERPLATE_IN_CI}" ]]; then |
| 60 | + git clone "${BOILERPLATE_GIT_REPO}" "${bp_clone}" |
| 61 | + else |
| 62 | + # HACK: We can't get around safe.directory in CI, so just leverage cp instead of git |
| 63 | + cp -r /go/src/github.com/openshift/boilerplate/* "${bp_clone}" |
| 64 | + cp -r /go/src/github.com/openshift/boilerplate/.git "${bp_clone}" |
| 65 | + fi |
| 66 | + cd "${bp_clone}" |
| 67 | + # Matches promote.sh |
| 68 | + git log --no-merges --pretty=format:'commit: %H%nauthor: %an%n%s%n%n%b%n%n' $bp_commit_change > $bp_log |
| 69 | + ) |
| 70 | + |
| 71 | +fi |
| 72 | + |
| 73 | +# Okay, let's look for convention changes. |
| 74 | +# TODO: Handle unsubscribes (not yet handled by the main `update` either). |
| 75 | +while read convention junk; do |
| 76 | + # TODO: These first few conditions, scrubbing the config file, are |
| 77 | + # identical to what's in `update`. It would be lovely to library-ize |
| 78 | + # them. However, `update` needs to remain self-contained since it's |
| 79 | + # part of the bootstrap process. |
| 80 | + |
| 81 | + # Skip comment lines (which can have leading whitespace) |
| 82 | + if [[ "$convention" == '#'* ]]; then |
| 83 | + continue |
| 84 | + fi |
| 85 | + # Skip blank or whitespace-only lines |
| 86 | + if [[ "$convention" == "" ]]; then |
| 87 | + continue |
| 88 | + fi |
| 89 | + # Lines like |
| 90 | + # valid/path other_junk |
| 91 | + # are not acceptable, unless `other_junk` is a comment |
| 92 | + if [[ "$junk" != "" ]] && [[ "$junk" != '#'* ]]; then |
| 93 | + echo "Invalid config! Only one convention is allowed per line. Found '$junk'. Ignoring." |
| 94 | + # `update` bails for this. We're being a bit more forgiving. |
| 95 | + continue |
| 96 | + fi |
| 97 | + |
| 98 | + dir_path="boilerplate/${convention}" |
| 99 | + # Make sure the directory exists |
| 100 | + if ! [[ -d "$dir_path" ]]; then |
| 101 | + echo "Invalid convention directory: '$convention'." |
| 102 | + echo "(Could be because we don't handle unsubscribing yet.)" |
| 103 | + echo "Ignoring." |
| 104 | + # `update` bails for this. We're being a bit more forgiving. |
| 105 | + continue |
| 106 | + fi |
| 107 | + |
| 108 | + # Okay, we have a legit convention. Let's see if the current checkout |
| 109 | + # touches it |
| 110 | + # (Note that we're reusing the same temp file on each iteration.) |
| 111 | + git status --porcelain $dir_path > $convention_status |
| 112 | + if ! [[ -s $convention_status ]]; then |
| 113 | + # No deltas here. |
| 114 | + echo "- $convention: No change" >> $convention_statuses |
| 115 | + |
| 116 | + elif grep -q -v '^??' $convention_status; then |
| 117 | + # If there's anything *other than* untracked, this was an update |
| 118 | + echo "- $convention: Update" >> $convention_statuses |
| 119 | + |
| 120 | + else |
| 121 | + # If we get here, everything is '^??' (untracked), meaning this is a |
| 122 | + # new subscription. (Or, I suppose, the convention was previously |
| 123 | + # empty? We'll call it a new subscription anyway.) |
| 124 | + echo "- $convention: Subscribe" >> $convention_statuses |
| 125 | + fi |
| 126 | + |
| 127 | +done < boilerplate/update.cfg |
| 128 | + |
| 129 | +# Let's make sure *something* boilerplate-related is happening here. |
| 130 | +if [[ -z "$bootstrap" ]] && [[ -z "$bp_commit_change" ]] && ! grep -v -q "No change" $convention_statuses; then |
| 131 | + err "No boilerplate-related activity found in the current checkout!" |
| 132 | +fi |
| 133 | + |
| 134 | +# Okay, we're ready to do this. |
| 135 | +# Generate the commit title and branch name indicating the *main* action |
| 136 | +# we're taking. This is 'bootstrap' or 'update'; or if we're doing |
| 137 | +# neither of those things and only changing config, 'subscribe'. |
| 138 | +# => Commit titles will be of one of the following forms: |
| 139 | +# "Boilerplate: Bootstrap at {hash}" |
| 140 | +# "Boilerplate: Update to {hash}" |
| 141 | +# "Boilerplate: Subscribe at {hash}" |
| 142 | +# => Branch names will be of the form: |
| 143 | +# boilerplate-{bootstrap|update|subscribe}-{N}-{hash} |
| 144 | +# where {N} is the number of configured conventions (omitted if zero) |
| 145 | +title="Boilerplate:" |
| 146 | +branch=boilerplate |
| 147 | +if [[ -n "$bootstrap" ]]; then |
| 148 | + title="$title Bootstrap at" |
| 149 | + branch="$branch-bootstrap" |
| 150 | +elif [[ -n "$bp_commit_change" ]]; then |
| 151 | + title="$title Update to" |
| 152 | + branch="$branch-update" |
| 153 | +else |
| 154 | + title="$title Subscribe at" |
| 155 | + branch="$branch-subscribe" |
| 156 | +fi |
| 157 | +cur_commit=$(cat boilerplate/_data/last-boilerplate-commit) |
| 158 | +title="$title $cur_commit" |
| 159 | +echo "$title |
| 160 | +" > $commit_message |
| 161 | + |
| 162 | +if [[ -n "$bootstrap" ]]; then |
| 163 | + echo "https://github.com/openshift/boilerplate/commit/$cur_commit |
| 164 | +---" >> $commit_message |
| 165 | +fi |
| 166 | + |
| 167 | +echo "Conventions:" >> $commit_message |
| 168 | +if [[ -s $convention_statuses ]]; then |
| 169 | + cat $convention_statuses >> $commit_message |
| 170 | + # Add the number of conventions to the branch name |
| 171 | + branch="$branch-"$(wc -l $convention_statuses | sed 's/ .*//') |
| 172 | +else |
| 173 | + echo " None." >> $commit_message |
| 174 | +fi |
| 175 | + |
| 176 | +branch="$branch-$cur_commit" |
| 177 | + |
| 178 | +if [[ -n "$bp_commit_change" ]]; then |
| 179 | + |
| 180 | + echo "--- |
| 181 | +$bp_compare_url |
| 182 | +" >> $commit_message |
| 183 | +cat $bp_log >> $commit_message |
| 184 | + |
| 185 | +fi |
| 186 | + |
| 187 | +# TODO: Handle branch name conflict. At the moment, this should really only be |
| 188 | +# possible if unsubscribing and subscribing the same number of conventions. |
| 189 | +# Since we don't handle unsubscribing (properly), we'll take our chances that |
| 190 | +# it "can't" happen for now. |
| 191 | +git checkout -b $branch |
| 192 | +# We can get away with -A because `update` forces a clean checkout. |
| 193 | +git add -A |
| 194 | +git commit -F $commit_message |
| 195 | +echo "Ready to push branch $branch" |
0 commit comments