1 #!/bin/bash 2 # Copyright 2012 the V8 project authors. All rights reserved. 3 # Redistribution and use in source and binary forms, with or without 4 # modification, are permitted provided that the following conditions are 5 # met: 6 # 7 # * Redistributions of source code must retain the above copyright 8 # notice, this list of conditions and the following disclaimer. 9 # * Redistributions in binary form must reproduce the above 10 # copyright notice, this list of conditions and the following 11 # disclaimer in the documentation and/or other materials provided 12 # with the distribution. 13 # * Neither the name of Google Inc. nor the names of its 14 # contributors may be used to endorse or promote products derived 15 # from this software without specific prior written permission. 16 # 17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29 30 ########## Global variable definitions 31 32 BRANCHNAME=prepare-push 33 TRUNKBRANCH=trunk-push 34 PERSISTFILE_BASENAME=/tmp/v8-push-to-trunk-tempfile 35 CHROME_PATH= 36 37 ########## Function definitions 38 39 source $(dirname $BASH_SOURCE)/common-includes.sh 40 41 usage() { 42 cat << EOF 43 usage: $0 OPTIONS 44 45 Performs the necessary steps for a V8 push to trunk. Only works for \ 46 git checkouts. 47 48 OPTIONS: 49 -h Show this message 50 -s Specify the step where to start work. Default: 0. 51 -l Manually specify the git commit ID of the last push to trunk. 52 -c Specify the path to your Chromium src/ directory to automate the 53 V8 roll. 54 EOF 55 } 56 57 ########## Option parsing 58 59 while getopts ":hs:l:c:" OPTION ; do 60 case $OPTION in 61 h) usage 62 exit 0 63 ;; 64 s) START_STEP=$OPTARG 65 ;; 66 l) LASTPUSH=$OPTARG 67 ;; 68 c) CHROME_PATH=$OPTARG 69 ;; 70 ?) echo "Illegal option: -$OPTARG" 71 usage 72 exit 1 73 ;; 74 esac 75 done 76 77 78 ########## Regular workflow 79 80 initial_environment_checks 81 82 if [ $START_STEP -le $CURRENT_STEP ] ; then 83 echo ">>> Step $CURRENT_STEP: Preparation" 84 common_prepare 85 delete_branch $TRUNKBRANCH 86 fi 87 88 let CURRENT_STEP+=1 89 if [ $START_STEP -le $CURRENT_STEP ] ; then 90 echo ">>> Step $CURRENT_STEP: Create a fresh branch." 91 git checkout -b $BRANCHNAME svn/bleeding_edge \ 92 || die "Creating branch $BRANCHNAME failed." 93 fi 94 95 let CURRENT_STEP+=1 96 if [ $START_STEP -le $CURRENT_STEP ] ; then 97 echo ">>> Step $CURRENT_STEP: Detect commit ID of last push to trunk." 98 [[ -n "$LASTPUSH" ]] || LASTPUSH=$(git log -1 --format=%H ChangeLog) 99 LOOP=1 100 while [ $LOOP -eq 1 ] ; do 101 # Print assumed commit, circumventing git's pager. 102 git log -1 $LASTPUSH | cat 103 confirm "Is the commit printed above the last push to trunk?" 104 if [ $? -eq 0 ] ; then 105 LOOP=0 106 else 107 LASTPUSH=$(git log -1 --format=%H $LASTPUSH^ ChangeLog) 108 fi 109 done 110 persist "LASTPUSH" 111 fi 112 113 let CURRENT_STEP+=1 114 if [ $START_STEP -le $CURRENT_STEP ] ; then 115 echo ">>> Step $CURRENT_STEP: Prepare raw ChangeLog entry." 116 # These version numbers are used again later for the trunk commit. 117 read_and_persist_version 118 119 DATE=$(date +%Y-%m-%d) 120 persist "DATE" 121 echo "$DATE: Version $MAJOR.$MINOR.$BUILD" > "$CHANGELOG_ENTRY_FILE" 122 echo "" >> "$CHANGELOG_ENTRY_FILE" 123 COMMITS=$(git log $LASTPUSH..HEAD --format=%H) 124 for commit in $COMMITS ; do 125 # Get the commit's title line. 126 git log -1 $commit --format="%w(80,8,8)%s" >> "$CHANGELOG_ENTRY_FILE" 127 # Grep for "BUG=xxxx" lines in the commit message and convert them to 128 # "(issue xxxx)". 129 git log -1 $commit --format="%B" \ 130 | grep "^BUG=" | grep -v "BUG=$" | grep -v "BUG=none$" \ 131 | sed -e 's/^/ /' \ 132 | sed -e 's/BUG=v8:\(.*\)$/(issue \1)/' \ 133 | sed -e 's/BUG=chromium:\(.*\)$/(Chromium issue \1)/' \ 134 | sed -e 's/BUG=\(.*\)$/(Chromium issue \1)/' \ 135 >> "$CHANGELOG_ENTRY_FILE" 136 # Append the commit's author for reference. 137 git log -1 $commit --format="%w(80,8,8)(%an)" >> "$CHANGELOG_ENTRY_FILE" 138 echo "" >> "$CHANGELOG_ENTRY_FILE" 139 done 140 echo " Performance and stability improvements on all platforms." \ 141 >> "$CHANGELOG_ENTRY_FILE" 142 fi 143 144 let CURRENT_STEP+=1 145 if [ $START_STEP -le $CURRENT_STEP ] ; then 146 echo ">>> Step $CURRENT_STEP: Edit ChangeLog entry." 147 echo -n "Please press <Return> to have your EDITOR open the ChangeLog entry, \ 148 then edit its contents to your liking. When you're done, save the file and \ 149 exit your EDITOR. " 150 read ANSWER 151 $EDITOR "$CHANGELOG_ENTRY_FILE" 152 NEWCHANGELOG=$(mktemp) 153 # Eliminate any trailing newlines by going through a shell variable. 154 # Also (1) eliminate tabs, (2) fix too little and (3) too much indentation, 155 # and (4) eliminate trailing whitespace. 156 CHANGELOGENTRY=$(cat "$CHANGELOG_ENTRY_FILE" \ 157 | sed -e 's/\t/ /g' \ 158 | sed -e 's/^ \{1,7\}\([^ ]\)/ \1/g' \ 159 | sed -e 's/^ \{9,80\}\([^ ]\)/ \1/g' \ 160 | sed -e 's/ \+$//') 161 [[ -n "$CHANGELOGENTRY" ]] || die "Empty ChangeLog entry." 162 echo "$CHANGELOGENTRY" > "$NEWCHANGELOG" 163 echo "" >> "$NEWCHANGELOG" # Explicitly insert two empty lines. 164 echo "" >> "$NEWCHANGELOG" 165 cat ChangeLog >> "$NEWCHANGELOG" 166 mv "$NEWCHANGELOG" ChangeLog 167 fi 168 169 let CURRENT_STEP+=1 170 if [ $START_STEP -le $CURRENT_STEP ] ; then 171 echo ">>> Step $CURRENT_STEP: Increment version number." 172 restore_if_unset "BUILD" 173 NEWBUILD=$(($BUILD + 1)) 174 confirm "Automatically increment BUILD_NUMBER? (Saying 'n' will fire up \ 175 your EDITOR on $VERSION_FILE so you can make arbitrary changes. When \ 176 you're done, save the file and exit your EDITOR.)" 177 if [ $? -eq 0 ] ; then 178 sed -e "/#define BUILD_NUMBER/s/[0-9]*$/$NEWBUILD/" \ 179 -i "$VERSION_FILE" 180 else 181 $EDITOR "$VERSION_FILE" 182 fi 183 read_and_persist_version "NEW" 184 fi 185 186 let CURRENT_STEP+=1 187 if [ $START_STEP -le $CURRENT_STEP ] ; then 188 echo ">>> Step $CURRENT_STEP: Commit to local branch." 189 restore_version_if_unset "NEW" 190 PREPARE_COMMIT_MSG="Prepare push to trunk. \ 191 Now working on version $NEWMAJOR.$NEWMINOR.$NEWBUILD." 192 persist "PREPARE_COMMIT_MSG" 193 git commit -a -m "$PREPARE_COMMIT_MSG" \ 194 || die "'git commit -a' failed." 195 fi 196 197 upload_step 198 199 let CURRENT_STEP+=1 200 if [ $START_STEP -le $CURRENT_STEP ] ; then 201 echo ">>> Step $CURRENT_STEP: Commit to the repository." 202 wait_for_lgtm 203 # Re-read the ChangeLog entry (to pick up possible changes). 204 cat ChangeLog | awk --posix '{ 205 if ($0 ~ /^[0-9]{4}-[0-9]{2}-[0-9]{2}:/) { 206 if (in_firstblock == 1) { 207 exit 0; 208 } else { 209 in_firstblock = 1; 210 } 211 }; 212 print $0; 213 }' > "$CHANGELOG_ENTRY_FILE" 214 git cl dcommit || die "'git cl dcommit' failed, please try again." 215 fi 216 217 let CURRENT_STEP+=1 218 if [ $START_STEP -le $CURRENT_STEP ] ; then 219 echo ">>> Step $CURRENT_STEP: Fetch straggler commits that sneaked in \ 220 since this script was started." 221 git svn fetch || die "'git svn fetch' failed." 222 git checkout svn/bleeding_edge 223 restore_if_unset "PREPARE_COMMIT_MSG" 224 PREPARE_COMMIT_HASH=$(git log -1 --format=%H --grep="$PREPARE_COMMIT_MSG") 225 persist "PREPARE_COMMIT_HASH" 226 fi 227 228 let CURRENT_STEP+=1 229 if [ $START_STEP -le $CURRENT_STEP ] ; then 230 echo ">>> Step $CURRENT_STEP: Squash commits into one." 231 # Instead of relying on "git rebase -i", we'll just create a diff, because 232 # that's easier to automate. 233 restore_if_unset "PREPARE_COMMIT_HASH" 234 git diff svn/trunk $PREPARE_COMMIT_HASH > "$PATCH_FILE" 235 # Convert the ChangeLog entry to commit message format: 236 # - remove date 237 # - remove indentation 238 # - merge paragraphs into single long lines, keeping empty lines between them. 239 restore_if_unset "DATE" 240 CHANGELOGENTRY=$(cat "$CHANGELOG_ENTRY_FILE") 241 echo "$CHANGELOGENTRY" \ 242 | sed -e "s/^$DATE: //" \ 243 | sed -e 's/^ *//' \ 244 | awk '{ 245 if (need_space == 1) { 246 printf(" "); 247 }; 248 printf("%s", $0); 249 if ($0 ~ /^$/) { 250 printf("\n\n"); 251 need_space = 0; 252 } else { 253 need_space = 1; 254 } 255 }' > "$COMMITMSG_FILE" || die "Commit message editing failed." 256 rm -f "$CHANGELOG_ENTRY_FILE" 257 fi 258 259 let CURRENT_STEP+=1 260 if [ $START_STEP -le $CURRENT_STEP ] ; then 261 echo ">>> Step $CURRENT_STEP: Create a new branch from trunk." 262 git checkout -b $TRUNKBRANCH svn/trunk \ 263 || die "Checking out a new branch '$TRUNKBRANCH' failed." 264 fi 265 266 let CURRENT_STEP+=1 267 if [ $START_STEP -le $CURRENT_STEP ] ; then 268 echo ">>> Step $CURRENT_STEP: Apply squashed changes." 269 rm -f "$TOUCHED_FILES_FILE" 270 apply_patch "$PATCH_FILE" 271 rm -f "$PATCH_FILE" 272 fi 273 274 let CURRENT_STEP+=1 275 if [ $START_STEP -le $CURRENT_STEP ] ; then 276 echo ">>> Step $CURRENT_STEP: Set correct version for trunk." 277 restore_version_if_unset 278 sed -e "/#define MAJOR_VERSION/s/[0-9]*$/$MAJOR/" \ 279 -e "/#define MINOR_VERSION/s/[0-9]*$/$MINOR/" \ 280 -e "/#define BUILD_NUMBER/s/[0-9]*$/$BUILD/" \ 281 -e "/#define PATCH_LEVEL/s/[0-9]*$/0/" \ 282 -e "/#define IS_CANDIDATE_VERSION/s/[0-9]*$/0/" \ 283 -i "$VERSION_FILE" || die "Patching $VERSION_FILE failed." 284 fi 285 286 let CURRENT_STEP+=1 287 if [ $START_STEP -le $CURRENT_STEP ] ; then 288 echo ">>> Step $CURRENT_STEP: Commit to local trunk branch." 289 git add "$VERSION_FILE" 290 git commit -F "$COMMITMSG_FILE" || die "'git commit' failed." 291 rm -f "$COMMITMSG_FILE" 292 fi 293 294 let CURRENT_STEP+=1 295 if [ $START_STEP -le $CURRENT_STEP ] ; then 296 echo ">>> Step $CURRENT_STEP: Sanity check." 297 confirm "Please check if your local checkout is sane: Inspect $VERSION_FILE, \ 298 compile, run tests. Do you want to commit this new trunk revision to the \ 299 repository?" 300 [[ $? -eq 0 ]] || die "Execution canceled." 301 fi 302 303 let CURRENT_STEP+=1 304 if [ $START_STEP -le $CURRENT_STEP ] ; then 305 echo ">>> Step $CURRENT_STEP: Commit to SVN." 306 git svn dcommit 2>&1 | tee >(grep -E "^Committed r[0-9]+" \ 307 | sed -e 's/^Committed r\([0-9]\+\)/\1/' \ 308 > "$TRUNK_REVISION_FILE") \ 309 || die "'git svn dcommit' failed." 310 TRUNK_REVISION=$(cat "$TRUNK_REVISION_FILE") 311 # Sometimes grepping for the revision fails. No idea why. If you figure 312 # out why it is flaky, please do fix it properly. 313 if [ -z "$TRUNK_REVISION" ] ; then 314 echo "Sorry, grepping for the SVN revision failed. Please look for it in \ 315 the last command's output above and provide it manually (just the number, \ 316 without the leading \"r\")." 317 while [ -z "$TRUNK_REVISION" ] ; do 318 echo -n "> " 319 read TRUNK_REVISION 320 done 321 fi 322 persist "TRUNK_REVISION" 323 rm -f "$TRUNK_REVISION_FILE" 324 fi 325 326 let CURRENT_STEP+=1 327 if [ $START_STEP -le $CURRENT_STEP ] ; then 328 echo ">>> Step $CURRENT_STEP: Tag the new revision." 329 restore_version_if_unset 330 git svn tag $MAJOR.$MINOR.$BUILD -m "Tagging version $MAJOR.$MINOR.$BUILD" \ 331 || die "'git svn tag' failed." 332 fi 333 334 if [ -z "$CHROME_PATH" ] ; then 335 echo ">>> (asking for Chromium checkout)" 336 echo -n "Do you have a \"NewGit\" Chromium checkout and want this script \ 337 to automate creation of the roll CL? If yes, enter the path to (and including) \ 338 the \"src\" directory here, otherwise just press <Return>: " 339 read CHROME_PATH 340 fi 341 342 if [ -n "$CHROME_PATH" ] ; then 343 344 let CURRENT_STEP+=1 345 if [ $START_STEP -le $CURRENT_STEP ] ; then 346 echo ">>> Step $CURRENT_STEP: Switch to Chromium checkout." 347 V8_PATH=$(pwd) 348 persist "V8_PATH" 349 cd "$CHROME_PATH" 350 initial_environment_checks 351 # Check for a clean workdir. 352 [[ -z "$(git status -s -uno)" ]] \ 353 || die "Workspace is not clean. Please commit or undo your changes." 354 # Assert that the DEPS file is there. 355 [[ -w "DEPS" ]] || die "DEPS file not present or not writable; \ 356 current directory is: $(pwd)." 357 fi 358 359 let CURRENT_STEP+=1 360 if [ $START_STEP -le $CURRENT_STEP ] ; then 361 echo ">>> Step $CURRENT_STEP: Update the checkout and create a new branch." 362 git checkout master || die "'git checkout master' failed." 363 git pull || die "'git pull' failed, please try again." 364 restore_if_unset "TRUNK_REVISION" 365 git checkout -b "v8-roll-$TRUNK_REVISION" \ 366 || die "Failed to checkout a new branch." 367 fi 368 369 let CURRENT_STEP+=1 370 if [ $START_STEP -le $CURRENT_STEP ] ; then 371 echo ">>> Step $CURRENT_STEP: Create and upload CL." 372 # Patch DEPS file. 373 sed -r -e "/\"v8_revision\": /s/\"[0-9]+\"/\"$TRUNK_REVISION\"/" \ 374 -i DEPS 375 restore_version_if_unset 376 echo -n "Please enter the email address of a reviewer for the roll CL: " 377 read REVIEWER 378 git commit -am "Update V8 to version $MAJOR.$MINOR.$BUILD. 379 380 TBR=$REVIEWER" || die "'git commit' failed." 381 git cl upload --send-mail \ 382 || die "'git cl upload' failed, please try again." 383 echo "CL uploaded." 384 fi 385 386 let CURRENT_STEP+=1 387 if [ $START_STEP -le $CURRENT_STEP ] ; then 388 echo ">>> Step $CURRENT_STEP: Returning to V8 checkout." 389 restore_if_unset "V8_PATH" 390 cd "$V8_PATH" 391 fi 392 fi # if [ -n "$CHROME_PATH" ] 393 394 let CURRENT_STEP+=1 395 if [ $START_STEP -le $CURRENT_STEP ] ; then 396 echo ">>> Step $CURRENT_STEP: Done!" 397 restore_version_if_unset 398 restore_if_unset "TRUNK_REVISION" 399 if [ -n "$CHROME_PATH" ] ; then 400 echo "Congratulations, you have successfully created the trunk revision \ 401 $MAJOR.$MINOR.$BUILD and rolled it into Chromium. Please don't forget to \ 402 update the v8rel spreadsheet:" 403 else 404 echo "Congratulations, you have successfully created the trunk revision \ 405 $MAJOR.$MINOR.$BUILD. Please don't forget to roll this new version into \ 406 Chromium, and to update the v8rel spreadsheet:" 407 fi 408 echo -e "$MAJOR.$MINOR.$BUILD\ttrunk\t$TRUNK_REVISION" 409 common_cleanup 410 [[ "$TRUNKBRANCH" != "$CURRENT_BRANCH" ]] && git branch -D $TRUNKBRANCH 411 fi 412