#!/usr/bin/env node /* * jQuery Core Release Management */ // Debugging variables var debug = false, skipRemote = true; var fs = require("fs"), child = require("child_process"), path = require("path"), which = require('which').sync; var releaseVersion, nextVersion, finalFiles, isBeta, pkg, 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", branch = "master", // Windows needs the .cmd version but will find the non-.cmd // On Windows, ensure the HOME environment variable is set gruntCmd = process.platform === "win32" ? "grunt.cmd" : "grunt", devFile = "dist/jquery.js", minFile = "dist/jquery.min.js", releaseFiles = { "jquery-VER.js": devFile, "jquery-VER.min.js": minFile, "jquery.js": devFile, "jquery-latest.js": devFile, "jquery.min.js": minFile, "jquery-latest.min.js": minFile }; steps( initialize, checkGitStatus, tagReleaseVersion, gruntBuild, makeReleaseCopies, setNextVersion, uploadToCDN, pushToGithub, exit ); function initialize( next ) { // First arg should be the version number being released var newver, oldver, rversion = /^(\d)\.(\d+)\.(\d)((?:a|b|rc)\d|pre)?$/, version = ( process.argv[2] || "" ).toLowerCase().match( rversion ) || {}, major = version[1], minor = version[2], patch = version[3], xbeta = version[4]; releaseVersion = process.argv[2]; isBeta = !!xbeta; if ( !major || !minor || !patch ) { die( "Usage: " + process.argv[1] + " releaseVersion" ); } if ( xbeta === "pre" ) { die( "Cannot release a 'pre' version!" ); } if ( !(fs.existsSync || path.existsSync)( "package.json" ) ) { die( "No package.json in this directory" ); } if ( debug ) { console.warn("=== DEBUG MODE ===" ); } pkg = JSON.parse( fs.readFileSync( "package.json" ) ); console.log( "Current version is " + pkg.version + "; generating release " + releaseVersion ); version = pkg.version.match( rversion ); oldver = ( +version[1] ) * 10000 + ( +version[2] * 100 ) + ( +version[3] ) newver = ( +major ) * 10000 + ( +minor * 100 ) + ( +patch ); if ( newver < oldver ) { die( "Next version is older than current version!" ); } nextVersion = major + "." + minor + "." + ( isBeta ? patch : +patch + 1 ) + "pre"; next(); } function checkGitStatus( next ) { exec( "git status", function( error, stdout, stderr ) { if ( /Changes to be committed/i.test( stdout ) ) { die( "Please commit changed files before attemping to push a release." ); } if ( /Changes not staged for commit/i.test( stdout ) ) { die( "Please stash files before attempting to push a release." ); } next(); }); } function tagReleaseVersion( next ) { updatePackageVersion( releaseVersion ); exec( 'git commit -a -m "Tagging the ' + releaseVersion + ' release."', function(){ exec( "git tag " + releaseVersion, next); }); } function gruntBuild( next ) { exec( gruntCmd, next ); } function makeReleaseCopies( next ) { finalFiles = {}; Object.keys( releaseFiles ).forEach(function( key ) { var builtFile = releaseFiles[ key ], releaseFile = key.replace( /VER/g, releaseVersion ); // Beta releases don't update the jquery-latest etc. copies if ( !isBeta || key !== releaseFile ) { copy( builtFile, releaseFile ); finalFiles[ releaseFile ] = builtFile; } }); next(); } function setNextVersion( next ) { updatePackageVersion( nextVersion ); exec( 'git commit -a -m "Updating the source version to ' + nextVersion + '"', next ); } function uploadToCDN( next ) { var cmds = []; Object.keys( finalFiles ).forEach(function( name ) { cmds.push(function( x ){ exec( "scp " + name + " " + scpURL, x, skipRemote ); }); cmds.push(function( x ){ exec( "curl '" + cdnURL + name + "?reload'", x, skipRemote ); }); }); cmds.push( next ); steps.apply( this, cmds ); } function pushToGithub( next ) { exec("git push --tags "+ repoURL + " " + branch, next, skipRemote ); } //============================== function steps() { var cur = 0, steps = arguments; (function next(){ var step = steps[ cur++ ]; step( next ); })(); } function updatePackageVersion( ver ) { console.log( "Updating package.json version to " + ver ); pkg.version = ver; if ( !debug ) { fs.writeFileSync( "package.json", JSON.stringify( pkg, null, "\t" ) + "\n" ); } } function copy( oldFile, newFile ) { console.log( "Copying " + oldFile + " to " + newFile ); if ( !debug ) { fs.writeFileSync( newFile, fs.readFileSync( oldFile, "utf8" ) ); } } function exec( cmd, fn, skip ) { if ( debug || skip ) { console.log( "# " + cmd ); fn(); } else { console.log( cmd ); child.exec( cmd, { env: process.env }, function( err, stdout, stderr ) { if ( err ) { die( stderr || stdout || err ); } fn(); }); } } function die( msg ) { console.error( "ERROR: " + msg ); process.exit( 1 ); } function exit() { process.exit( 0 ); }