]> source.dussan.org Git - jquery-ui.git/commitdiff
Build: New release script.
authorScott González <scott.gonzalez@gmail.com>
Fri, 20 Jul 2012 00:49:07 +0000 (20:49 -0400)
committerScott González <scott.gonzalez@gmail.com>
Fri, 20 Jul 2012 00:49:07 +0000 (20:49 -0400)
build/release/prepare-release [deleted file]
build/release/release.js [new file with mode: 0644]

diff --git a/build/release/prepare-release b/build/release/prepare-release
deleted file mode 100755 (executable)
index 91665e1..0000000
+++ /dev/null
@@ -1,336 +0,0 @@
-#!/bin/sh
-
-base_dir="`pwd`/jquery-ui-release"
-repo_dir="$base_dir/jquery-ui"
-release_dir="$repo_dir/build/release"
-
-github_repo="git@github.com:jquery/jquery-ui.git"
-remote_cmd="ssh jqadmin@ui-dev.jquery.com /srv/dev.jqueryui.com/prepare-release"
-
-
-
-#
-# Setup environment
-#
-
-echo
-echo "--------------------------"
-echo "| SETTING UP ENVIRONMENT |"
-echo "--------------------------"
-echo
-
-mkdir $base_dir
-cd $base_dir
-
-echo "Cloning repo from $github_repo..."
-git clone $github_repo
-cd $repo_dir
-
-echo
-echo "Environment setup complete."
-echo
-
-
-
-#
-# Figure out which versions we're dealing with
-#
-
-echo
-echo "------------------------"
-echo "| CALCULATING VERSIONS |"
-echo "------------------------"
-echo
-
-# NOTE: this will be different for minor and major releases
-version=`$remote_cmd/get-latest-version`
-major_minor=${version%.*}
-point=${version##*.}
-version_new="${major_minor}.$(($point + 1))"
-version_next=`cat version.txt`
-
-echo "We are going from $version to $version_new."
-echo "version.txt will be set to $version_next when complete."
-echo "Press enter to continue, or ctrl+c to cancel."
-read
-
-
-#
-# Generate shell for changelog
-#
-
-echo
-echo "------------------------"
-echo "| GENERATING CHANGELOG |"
-echo "------------------------"
-echo
-
-echo "Creating shell for changelog..."
-changelog_url="http:\/\/docs.jquery.com\/action\/edit\/UI\/Changelog\/$version_new"
-`sed "s/CHANGELOG_URL/$changelog_url/" <$release_dir/changelog-shell >$base_dir/changelog`
-
-
-# find all commits
-echo "Adding commits to changelog..."
-format_ticket='[http://dev.jqueryui.com/ticket/XXXX #XXXX]'
-format_commit='[http://github.com/jquery/jquery-ui/commit/%H %h]'
-format_full="* %s ($format_ticket, $format_commit)"
-git whatchanged $version... --pretty=format:"$format_full" \
-  -- ui themes demos build \
-| sed '/^:/ d' \
-| sed '/^$/ d' \
-| sed 's/\(Fixe[sd] #\)\([0-9][0-9]*\)\(.*\)\(XXXX #XXXX\)/Fixed #\2\3\2 #\2/' \
-| LC_ALL='C' sort -f \
->> $base_dir/changelog
-
-# find all fixed tickets
-echo "Adding Trac tickets to changelog..."
-$remote_cmd/generate-changelog >> $base_dir/changelog
-
-echo
-echo "Changelog complete."
-echo
-
-
-
-#
-# Generate list of contributors
-#
-
-echo
-echo "--------------------------"
-echo "| GATHERING CONTRIBUTORS |"
-echo "--------------------------"
-echo
-
-
-# find all committers and authors
-echo "Adding commiters and authors..."
-format_contributors='%aN%n%cN'
-git whatchanged $version... --pretty=format:"$format_contributors" \
-| sed '/^:/ d' \
-| sed '/^$/ d' \
-> $base_dir/thankyou
-
-# find all reporters and commenters from Trac
-echo "Adding reporters and commenters from Trac..."
-$remote_cmd/generate-contributors >> $base_dir/thankyou
-
-# sort names
-echo "Sorting contributors..."
-LC_ALL='C' sort -f $base_dir/thankyou | uniq > $base_dir/_thankyou
-mv $base_dir/_thankyou $base_dir/thankyou
-
-# find all people that were thanked
-echo "Adding people thanked in commits..."
-git whatchanged $version... \
-| grep -i thank \
->> $base_dir/thankyou
-
-echo
-echo "Find contributors from duplicates of fixed tickets and add them to:"
-echo "$base_dir/thankyou"
-echo "Press enter when done."
-read
-
-echo
-echo "Contributors list complete."
-echo
-
-
-
-#
-# Update version
-#
-
-echo
-echo "--------------------"
-echo "| UPDATING VERSION |"
-echo "--------------------"
-echo
-
-echo "Updating version.txt to $version_new..."
-echo $version_new > version.txt
-
-git commit -a -m "Tagging the $version_new release."
-version_new_time=`git log -1 --pretty=format:"%ad"`
-echo "Committed version.txt at $version_new_time..."
-
-echo "Tagging $version_new..."
-git tag $version_new
-
-echo "Updating version.txt to $version_next..."
-echo $version_next > version.txt
-
-git commit -a -m "Updating the master version to $version_next"
-echo "Committed version.txt..."
-
-echo
-echo "Version update complete."
-echo
-
-
-
-#
-# Push to GitHub
-#
-
-echo
-echo "---------------------"
-echo "| PUSHING TO GITHUB |"
-echo "---------------------"
-echo
-
-echo "Please review the output and generated files as a sanity check."
-echo "Press enter to continue or ctrl+c to abort."
-read
-
-git push
-git push --tags
-
-echo
-echo "Push to GitHub complete."
-echo
-
-
-
-#
-# Update Trac
-#
-
-echo
-echo "-----------------"
-echo "| UPDATING TRAC |"
-echo "-----------------"
-echo
-
-# TODO: automate this
-# NOTE: this will be different for minor and major releases
-milestone=`$remote_cmd/get-latest-milestone`
-
-# Create new milestrone and version
-echo "$version_new was tagged at $version_new_time."
-echo "Create and close the $version_new Milestone with the above date and time."
-echo "Create the $version_new Version with the above date and time."
-echo "Press enter when done."
-read
-
-# Update milestone for all fixed tickets
-echo "Change all $milestone fixed tickets to $version_new."
-echo "Press enter when done."
-read
-
-echo
-echo "Trac updates complete."
-echo
-
-
-
-#
-# Build jQuery UI
-#
-
-echo
-echo "----------------------"
-echo "| BUILDING JQUERY UI |"
-echo "----------------------"
-echo
-
-# check out the tagged version
-echo "Checking out $version_new..."
-git checkout $version_new
-cd build
-
-# Update the link to the docs (never contains the patch version)
-echo "Updating URL for API docs..."
-sed "s/UI\/API\/\${release\.version}/UI\/API\/$major_minor/" build.xml >build.xml.tmp
-mv build.xml.tmp build.xml
-
-# Run the build
-echo "Running build..."
-ant
-
-echo
-echo "Build complete."
-echo
-
-
-
-#
-# Upload zip to Google Code
-#
-
-echo
-echo "----------------------"
-echo "| UPDATE GOOGLE CODE |"
-echo "----------------------"
-echo
-
-echo "Upload zip to Google Code."
-echo "  http://code.google.com/p/jquery-ui/downloads/entry"
-echo "  Summary: jQuery UI $version_new (Source, demos, docs, themes, tests) STABLE"
-echo "  Labels: Featured, Type-Source, OpSys-All"
-echo "Modify the previous release to no longer say STABLE at the end."
-echo "Remove the featured label from the previous release."
-echo "Press enter when done."
-read
-
-echo
-echo "Google Code update complete."
-echo
-
-
-
-#
-# Update SVN
-#
-
-echo
-echo "----------------"
-echo "| UPDATING SVN |"
-echo "----------------"
-echo
-
-cd $base_dir
-mkdir svn
-cd svn
-
-echo "Checking out SVN tags..."
-svn co --depth immediates https://jquery-ui.googlecode.com/svn/tags
-cd tags
-
-echo "Unzipping build into tags/$version_new..."
-unzip $repo_dir/build/dist/jquery-ui-$version_new.zip
-mv jquery-ui-$version_new $version_new
-
-echo "Adding files to SVN..."
-svn add $version_new
-
-echo "Setting svn:mime-type..."
-find $version_new -name \*.js -exec svn propset svn:mime-type text/javascript {} \;
-find $version_new -name \*.css -exec svn propset svn:mime-type text/css {} \;
-find $version_new -name \*.html -exec svn propset svn:mime-type text/html {} \;
-find $version_new -name \*.png -exec svn propset svn:mime-type image/png {} \;
-find $version_new -name \*.gif -exec svn propset svn:mime-type image/gif {} \;
-
-# TODO: commit
-echo
-echo "svn commit with the following message:"
-echo "Created $version_new tag from http://jquery-ui.googlecode.com/files/jquery-ui-$version_new.zip"
-echo "Press enter when done."
-read
-
-echo
-echo "SVN update complete."
-echo
-
-
-
-#
-# Generate themes
-# 
-
-
-
-
-# ruby -e 'puts File.read("thankyou").split("\n").join(", ")' > thankyou2
diff --git a/build/release/release.js b/build/release/release.js
new file mode 100644 (file)
index 0000000..e86ebef
--- /dev/null
@@ -0,0 +1,381 @@
+#!/usr/bin/env node
+
+var baseDir, repoDir, prevVersion, newVersion, nextVersion, tagTime,
+       fs = require( "fs" ),
+       rnewline = /\r?\n/,
+       repo = "git@github.com:jquery/jquery-ui.git",
+       branch = "master";
+
+walk([
+       bootstrap,
+
+       section( "setting up repo" ),
+       cloneRepo,
+       checkState,
+
+       section( "calculating versions" ),
+       getVersions,
+       confirm,
+
+       section( "tagging release" ),
+       tagRelease,
+       confirm,
+       pushRelease,
+
+       section( "updating branch version" ),
+       updateBranchVersion,
+       confirm,
+       pushBranch,
+
+       section( "generating changelog" ),
+       generateChangelog,
+
+       section( "gathering contributors" ),
+       gatherContributors,
+
+       section( "updating trac" ),
+       updateTrac,
+       confirm,
+
+       section( "building release" ),
+       buildRelease
+]);
+
+
+
+
+
+function cloneRepo() {
+       if ( test( "-d", baseDir ) ) {
+               abort( "The directory '" + baseDir + "' already exists." );
+       }
+
+       echo( "Cloning " + repo + "..." );
+       git( "clone " + repo + " " + repoDir, "Error cloning repo." );
+       cd( repoDir );
+
+       echo( "Checking out " + branch + " branch..." );
+       git( "checkout " + branch, "Error checking out branch." );
+
+       echo( "Installing dependencies..." );
+       if ( exec( "npm install" ).code !== 0 ) {
+               abort( "Error installing dependencies." );
+       }
+}
+
+function checkState() {
+       echo( "Checking AUTHORS.txt..." );
+       var result, lastActualAuthor,
+               lastListedAuthor = cat( "AUTHORS.txt" ).trim().split( rnewline ).pop();
+
+       result = exec( "grunt authors", { silent: true });
+       if ( result.code !== 0 ) {
+               abort( "Error getting list of authors." );
+       }
+       lastActualAuthor = result.output.split( rnewline ).splice( -4, 1 )[ 0 ];
+
+       if ( lastListedAuthor !== lastActualAuthor ) {
+               echo( "Last listed author is " + lastListedAuthor + "." );
+               echo( "Last actual author is " + lastActualAuthor + "." );
+               abort( "Please update AUTHORS.txt." );
+       }
+
+       echo( "Last listed author (" + lastListedAuthor + ") is correct." );
+}
+
+function getVersions() {
+       // prevVersion, newVersion, nextVersion are defined in the parent scope
+       var parts, major, minor, patch,
+               currentVersion = readPackage().version;
+
+       echo( "Validating current version..." );
+       if ( currentVersion.substr( -3, 3 ) !== "pre" ) {
+               echo( "The current version is " + currentVersion + "." );
+               abort( "The version must be a pre version." );
+       }
+
+       newVersion = currentVersion.substr( 0, currentVersion.length - 3 );
+       parts = newVersion.split( "." );
+       major = parseInt( parts[ 0 ], 10 );
+       minor = parseInt( parts[ 1 ], 10 );
+       patch = parseInt( parts[ 2 ], 10 );
+       prevVersion = patch === 0 ?
+               [ major, minor - 1, 0 ].join( "." ) :
+               [ major, minor, patch - 1 ].join( "." );
+       // TODO: Remove version hack after 1.9.0 release
+       if ( prevVersion === "1.8.0" ) {
+               prevVersion = "1.8";
+       }
+       nextVersion = [ major, minor, patch + 1 ].join( "." ) + "pre";
+
+       echo( "We are going from " + prevVersion + " to " + newVersion + "." );
+       echo( "After the release, the version will be " + nextVersion + "." );
+}
+
+function tagRelease() {
+       var pkg;
+
+       echo( "Creating release branch..." );
+       git( "checkout -b release", "Error creating release branch." );
+
+       echo( "Updating package.json..." );
+       pkg = readPackage();
+       pkg.version = newVersion;
+       pkg.licenses.forEach(function( license ) {
+               license.url = license.url.replace( "master", newVersion );
+       });
+       writePackage( pkg );
+
+       echo( "Generating manifest files..." );
+       if ( exec( "grunt manifest" ).code !== 0 ) {
+               abort( "Error generating manifest files." );
+       }
+
+       echo( "Committing release artifacts..." );
+       git( "add *.jquery.json", "Error adding manifest files to git." );
+       git( "commit -am 'Tagging the " + newVersion + " release.'",
+               "Error committing release changes." );
+
+       echo( "Tagging release..." );
+       git( "tag " + newVersion, "Error tagging " + newVersion + "." );
+       tagTime = git( "log -1 --format='%ad'", "Error getting tag timestamp." ).trim();
+
+       echo();
+       echo( "Please review the output and generated files as a sanity check." );
+}
+
+function pushRelease() {
+       echo( "Pushing release to GitHub..." );
+       git( "push --tags", "Error pushing tags to GitHub." );
+}
+
+function updateBranchVersion() {
+       var pkg;
+
+       echo( "Checking out " + branch + " branch..." );
+       git( "checkout " + branch, "Error checking out " + branch + " branch." );
+
+       echo( "Updating package.json..." );
+       pkg = readPackage();
+       pkg.version = nextVersion;
+       writePackage( pkg );
+
+       echo( "Committing version update..." );
+       git( "commit -am 'Updating the " + branch + " version to " + nextVersion + ".'",
+               "Error committing package.json." );
+
+       echo();
+       echo( "Please review the output and generated files as a sanity check." );
+}
+
+function pushBranch() {
+       echo( "Pushing " + branch + " to GitHub..." );
+       git( "push", "Error pushing to GitHub." );
+}
+
+function generateChangelog() {
+       var commits,
+               changelogPath = baseDir + "/changelog",
+               changelog = cat( "build/release/changelog-shell" ) + "\n",
+               fullFormat = "* %s (TICKETREF, [http://github.com/jquery/jquery-ui/commit/%H %h])";
+
+       echo ( "Adding commits..." );
+       commits = gitLog( fullFormat );
+
+       echo( "Adding links to tickets..." );
+       changelog += commits
+               // Add ticket references
+               .map(function( commit ) {
+                       var tickets = [];
+                       // TODO: Don't use .replace() since we're not actually replacing
+                       commit.replace( /Fixe[sd] #(\d+)/g, function( match, ticket ) {
+                               tickets.push( ticket );
+                       });
+                       return tickets.length ?
+                               commit.replace( "TICKETREF", tickets.map(function( ticket ) {
+                                       return "[http://bugs.jqueryui.com/ticket/" + ticket + " #" + ticket + "]";
+                               }).join( ", " ) ) :
+                               // Leave TICKETREF token in place so it's easy to find commits without tickets
+                               commit;
+               })
+               // Sort commits so that they're grouped by component
+               .sort()
+               .join( "\n" ) + "\n";
+
+       echo( "Adding Trac tickets..." );
+       changelog += trac( "/query?milestone=" + newVersion + "&resolution=fixed" +
+               "&col=id&col=component&col=summary&order=component" ) + "\n";
+
+       fs.writeFileSync( changelogPath, changelog );
+       echo( "Stored changelog in " + changelogPath + "." );
+}
+
+function gatherContributors() {
+       var contributors,
+               contributorsPath = baseDir + "/contributors";
+
+       echo( "Adding committers and authors..." );
+       contributors = gitLog( "%aN%n%cN" );
+
+       echo( "Adding reporters and commenters from Trac..." );
+       contributors = contributors.concat(
+               trac( "/report/22?V=" + newVersion + "&max=-1" )
+                       .split( rnewline )
+                       .slice( 1, -1 ) );
+
+       echo( "Sorting contributors..." );
+       contributors = unique( contributors ).sort(function( a, b ) {
+               return a.toLowerCase() < b.toLowerCase() ? -1 : 1;
+       });
+
+       echo ( "Adding people thanked in commits..." );
+       contributors = contributors.concat(
+               gitLog( "%b%n%s" ).filter(function( line ) {
+                       return /thank/i.test( line );
+               }));
+
+       fs.writeFileSync( contributorsPath, contributors.join( "\n" ) );
+       echo( "Stored contributors in " + contributorsPath + "." );
+}
+
+function updateTrac() {
+       echo( newVersion + " was tagged at " + tagTime + "." );
+       echo( "Close the " + newVersion + " Milestone with the above date and time." );
+       echo( "Create the " + newVersion + " Version with the above date and time." );
+       echo( "Create a Milestone for the next minor release." );
+}
+
+function buildRelease() {
+       echo( "Checking out " + newVersion + "..." );
+       git( "checkout " + newVersion, "Error checking out " + newVersion + "." );
+
+       echo( "Building release..." );
+       if ( exec( "grunt release" ).code !== 0 ) {
+               abort( "Error building release." );
+       }
+}
+
+
+
+
+
+// ===== HELPER FUNCTIONS ======================================================
+
+function git( command, errorMessage ) {
+       var result = exec( "git " + command );
+       if ( result.code !== 0 ) {
+               abort( errorMessage );
+       }
+
+       return result.output;
+}
+
+function gitLog( format ) {
+       var result = exec( "git log " + prevVersion + ".." + newVersion + " " +
+               "--format='" + format + "'",
+               { silent: true });
+
+       if ( result.code !== 0 ) {
+               abort( "Error getting git log." );
+       }
+
+       result = result.output.split( rnewline );
+       if ( result[ result.length - 1 ] === "" ) {
+               result.pop();
+       }
+
+       return result;
+}
+
+function trac( path ) {
+       var result = exec( "curl -s 'http://bugs.jqueryui.com" + path + "&format=tab'",
+               { silent: true });
+
+       if ( result.code !== 0 ) {
+               abort( "Error getting Trac data." );
+       }
+
+       return result.output;
+}
+
+function unique( arr ) {
+       var obj = {};
+       arr.forEach(function( item ) {
+               obj[ item ] = 1;
+       });
+       return Object.keys( obj );
+}
+
+function readPackage() {
+       return JSON.parse( fs.readFileSync( repoDir + "/package.json" ) );
+}
+
+function writePackage( pkg ) {
+       fs.writeFileSync( repoDir + "/package.json",
+               JSON.stringify( pkg, null, "\t" ) + "\n" );
+}
+
+function bootstrap( fn ) {
+       require( "child_process" ).exec( "npm root -g", function( error, stdout ) {
+               if ( error ) {
+                       console.log( error );
+                       return process.exit( 1 );
+               }
+
+               var rootDir = stdout.trim();
+               require( rootDir + "/shelljs/global" );
+
+               baseDir = pwd() + "/__release";
+               repoDir = baseDir + "/repo";
+
+               fn();
+       });
+}
+
+function section( name ) {
+       var line = new Array( name.length + 5 ).join( "-" );
+       return function() {
+               echo();
+               // https://github.com/arturadib/shelljs/issues/20
+               console.log( line );
+               echo( "| " + name.toUpperCase() + " |" );
+               console.log( line );
+               echo();
+       };
+}
+
+function prompt( fn ) {
+       process.stdin.once( "data", function( chunk ) {
+               process.stdin.pause();
+               fn( chunk.toString().trim() );
+       });
+       process.stdin.resume();
+}
+
+function confirm( fn ) {
+       echo( "Press enter to continue, or ctrl+c to cancel." );
+       prompt( fn );
+}
+
+function abort( msg ) {
+       echo( msg );
+       echo( "Aborting." );
+       exit( 1 );
+}
+
+function walk( methods ) {
+       var method = methods.shift();
+
+       function next( error ) {
+               if ( methods.length ) {
+                       walk( methods );
+               }
+       }
+
+       if ( !method.length ) {
+               method();
+               next();
+       } else {
+               method( next );
+       }
+}