diff --git a/build/release.js b/build/release.js index 2a762cf08..1cc29d5e8 100644 --- a/build/release.js +++ b/build/release.js @@ -18,6 +18,8 @@ var releaseVersion, pkg, branch, + sizzleLoc = "bower_components/sizzle", + scpURL = "jqadmin@code.origin.jquery.com:/var/www/html/code.jquery.com/", cdnURL = "http://code.origin.jquery.com/", repoURL = "git@github.com:jquery/jquery.git", @@ -57,14 +59,16 @@ var releaseVersion, steps( initialize, checkGitStatus, - tagReleaseVersion, + setReleaseVersion, gruntBuild, + createTag, makeReleaseCopies, - setNextVersion, copyTojQueryCDN, buildGoogleCDN, buildMicrosoftCDN, + setNextVersion, pushToGithub, + publishToNpm, exit ); @@ -78,6 +82,7 @@ function initialize( next ) { // First arg should be the version number being released var newver, oldver, + exists = fs.existsSync || path.existsSync, rsemver = /^(\d+)\.(\d+)\.(\d+)(?:-([\dA-Za-z\-]+(?:\.[\dA-Za-z\-]+)*))?$/, version = ( process.argv[3] || "" ).toLowerCase().match( rsemver ) || {}, major = version[1], @@ -95,10 +100,13 @@ function initialize( next ) { if ( xbeta === "pre" ) { die( "Cannot release a 'pre' version!" ); } - if ( !(fs.existsSync || path.existsSync)( "package.json" ) ) { + if ( !exists( "package.json" ) ) { die( "No package.json in this directory" ); } - pkg = JSON.parse( fs.readFileSync( "package.json" ) ); + if ( !exists( sizzleLoc ) ) { + die( "Sizzle expected to exist at " + sizzleLoc ); + } + pkg = readJSON( "package.json" ); console.log( "Current version is " + pkg.version + "; generating release " + releaseVersion ); version = pkg.version.match( rsemver ); @@ -128,21 +136,22 @@ function checkGitStatus( next ) { }); } -function tagReleaseVersion( next ) { - updatePackageVersion( releaseVersion ); - git( [ "commit", "-a", "-m", "Tagging the " + releaseVersion + " release." ], function(){ - git( [ "tag", releaseVersion ], next, debug); - }, debug); +function setReleaseVersion( next ) { + updateVersion( releaseVersion ); + git( [ "commit", "-a", "-m", "Updating version to " + releaseVersion + "." ], next, debug ); } function gruntBuild( next ) { - exec( gruntCmd, [], function( error, stdout, stderr ) { - if ( error ) { - die( error + stderr ); - } - console.log( stdout ); - next(); - }, false ); + // First clean the dist directory of anything we're not about to rebuild + git( [ "clean", "-dfx", "dist/" ], function() { + exec( gruntCmd, [], function( error, stdout, stderr ) { + if ( error ) { + die( error + stderr ); + } + console.log( stdout ); + next(); + }, false ); + }, debug ); } function makeReleaseCopies( next ) { @@ -180,11 +189,6 @@ function makeReleaseCopies( next ) { next(); } -function setNextVersion( next ) { - updatePackageVersion( nextVersion ); - git( [ "commit", "-a", "-m", "Updating the source version to " + nextVersion + "✓™" ], next, debug ); -} - function copyTojQueryCDN( next ) { var cmds = []; @@ -209,12 +213,27 @@ function buildMicrosoftCDN( next ) { makeArchive( "mscdn", msFilesCDN, next ); } +function createTag( next ) { + steps( + checkoutCommit, + commitDistFiles, + tagRelease, + checkoutBranch, + next + ); +} + +function setNextVersion( next ) { + updateVersion( nextVersion ); + git( [ "commit", "-a", "-m", "Updating the source version to " + nextVersion + "✓™" ], next, debug ); +} + function pushToGithub( next ) { git( [ "push", "--tags", repoURL, branch ], next, debug || skipRemote ); } -//============================== - +/* Utilities +---------------------------------------------------------------------- */ function steps() { var cur = 0, st = arguments; @@ -225,14 +244,103 @@ function steps() { })(); } -function updatePackageVersion( ver ) { - console.log( "Updating package.json version to " + ver ); +function readJSON( filename ) { + return JSON.parse( fs.readFileSync( filename ) ); +} + +function replaceVersionJSON( file, version ) { + var text = fs.readFileSync( file, "utf8" ); + text = text.replace( /("version":\s*")[^"]+/, "$1" + version ); + fs.writeFileSync( file, text ); +} + +function updateVersion( ver ) { + console.log( "Updating version to " + ver ); pkg.version = ver; if ( !debug ) { - fs.writeFileSync( "package.json", JSON.stringify( pkg, null, "\t" ) + "\n" ); + [ "package.json", "bower.json" ].forEach(function( filename ) { + replaceVersionJSON( filename, ver ); + }); } } +function copy( oldFile, newFile, skip ) { + console.log( "Copying " + oldFile + " to " + newFile ); + if ( !skip ) { + fs.writeFileSync( newFile, fs.readFileSync( oldFile, "utf8" ) ); + } +} + +function exec( cmd, args, fn, skip ) { + if ( skip ) { + console.log( "# " + cmd + " " + args.join(" ") ); + fn( "", "", "" ); + } else { + console.log( cmd + " " + args.join(" ") ); + child.execFile( cmd, args, { env: process.env }, + function( err, stdout, stderr ) { + if ( err ) { + die( stderr || stdout || err ); + } + fn.apply( this, arguments ); + } + ); + } +} + +function git( args, fn, skip ) { + exec( "git", args, fn, skip ); +} + + +/* Tag creation +---------------------------------------------------------------------- */ +function checkoutCommit( next ) { + git( [ "checkout", "HEAD^0" ], next, debug ); +} + +function commitDistFiles( next ) { + // Remove scripts property from package.json + var pkgClone = readJSON( "package.json" ); + delete pkgClone.scripts; + fs.writeFileSync( "package.json", JSON.stringify( pkgClone, null, "\t" ) ); + fs.unlinkSync( ".gitignore" ); + // Add files to be committed + git( [ "add", "package.json", "dist", sizzleLoc ], function() { + // Remove unneeded files + git( [ "rm", "-r", + "build", + "speed", + "test", + ".editorconfig", + ".gitattributes", + ".gitignore", + ".jscs.json", + ".jshintignore", + ".jshintrc", + ".mailmap", + ".travis.yml", + "Gruntfile.js", + "README.md" + ], function() { + git( [ "commit", "-a", "-m", releaseVersion ], next, debug ); + }, debug ); + }, debug ); +} + +function tagRelease( next ) { + git( [ "tag", releaseVersion ], next, debug ); +} + +function checkoutBranch( next ) { + // Reset files to previous state before leaving the commit + git( [ "reset", "--hard", "HEAD" ], function() { + git( [ "checkout", branch ], next, debug ); + }, debug ); +} + +/* Archive creation +---------------------------------------------------------------------- */ function makeArchive( cdn, files, fn ) { if ( isBeta ) { console.log( "Skipping archive creation for " + cdn + "; " + releaseVersion + " is beta" ); @@ -269,34 +377,34 @@ function makeArchive( cdn, files, fn ) { }, false ); } -function copy( oldFile, newFile, skip ) { - console.log( "Copying " + oldFile + " to " + newFile ); - if ( !skip ) { - fs.writeFileSync( newFile, fs.readFileSync( oldFile, "utf8" ) ); +/* NPM +---------------------------------------------------------------------- */ +function publishToNpm( next ) { + // Only publish the master branch to NPM + // You must be the jquery npm user for this not to fail + // To check, run `npm whoami` + // Log in to the jquery user with `npm adduser` + if ( branch !== "master" ) { + next(); + return; } -} - -function git( args, fn, skip ) { - exec( "git", args, fn, skip ); -} - -function exec( cmd, args, fn, skip ) { - if ( skip ) { - console.log( "# " + cmd + " " + args.join(" ") ); - fn( "", "", "" ); - } else { - console.log( cmd + " " + args.join(" ") ); - child.execFile( cmd, args, { env: process.env }, - function( err, stdout, stderr ) { - if ( err ) { - die( stderr || stdout || err ); - } - fn.apply( this, arguments ); + git( [ "checkout", releaseVersion ], function() { + // Only publish committed files + git( [ "clean", "-dfx" ], function() { + var args = [ "publish" ]; + // Tag the version as beta if necessary + if ( isBeta ) { + args.push( "--tag", "beta" ); } - ); - } + exec( "npm", args, function() { + git( [ "checkout", branch ], next, debug ); + }, debug || skipRemote ); + }, debug ); + }, debug); } +/* Death +---------------------------------------------------------------------- */ function die( msg ) { console.error( "ERROR: " + msg ); process.exit( 1 );