diff --git a/.env.sample b/.env.sample index 8286a629b3..5006a97bcd 100644 --- a/.env.sample +++ b/.env.sample @@ -13,4 +13,6 @@ WP_TEST_MAILER_MAILPOET_API="" WP_TEST_MAILER_SENDGRID_API="" WP_TEST_MAILER_SMTP_HOST="" WP_TEST_MAILER_SMTP_LOGIN="" -WP_TEST_MAILER_SMTP_PASSWORD="" \ No newline at end of file +WP_TEST_MAILER_SMTP_PASSWORD="" +WP_SVN_USERNAME="" +WP_SVN_PASSWORD="" diff --git a/.gitignore b/.gitignore index bf68ac318b..bbba19d5cb 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,5 @@ tests/javascript/testBundles assets/css/*.css assets/js/*.js .vagrant -lang \ No newline at end of file +lang +.mp_svn diff --git a/README.md b/README.md index 88703b4171..fa67966383 100644 --- a/README.md +++ b/README.md @@ -128,3 +128,20 @@ _n() - Handlebars. You can use Twig i18n functions in Handlebars, just load your template from a Twig view. + +# Publish + +Before you run a publishing command, you need to: +1. Ensure there is an up-to-date local copy of MailPoet SVN repository in `.mp_svn` directory by running `./do svn:checkout`. +2. Have all your features merged in Git `master`, your `mailpoet.php` and `readme.txt` tagged with a new version. +3. Run `./build.sh` to produce a `mailpoet.zip` distributable archive. + +Everything's ready? Then run `./do svn:publish`. +If the job goes fine, you'll get a message like this: +``` +Go to '.mp_svn' and run 'svn ci -m "Release 3.0.0-beta.9"' to publish the +release +``` +It's quite literal: you can review the changes to be pushed and if you're satisfied, run the suggested command to finish the release publishing process. + +If you're confident, execute `./do svn:publish --force` and your release will be published to the remote SVN repository without manual intervention (automatically). For easier authentication you might want to set `WP_SVN_USERNAME` and `WP_SVN_PASSWORD` environment variables. diff --git a/RoboFile.php b/RoboFile.php index 25bef12d35..2ce755ba0c 100644 --- a/RoboFile.php +++ b/RoboFile.php @@ -192,8 +192,113 @@ class RoboFile extends \Robo\Tasks { ); } + function svnCheckout() { + return $this->_exec('svn co https://plugins.svn.wordpress.org/mailpoet/ .mp_svn'); + } + + function svnPublish($opts = ['force' => false]) { + $this->loadWP(); + + $svn_dir = ".mp_svn"; + $plugin_data = get_plugin_data('mailpoet.php'); + $plugin_version = $plugin_data['Version']; + $plugin_dist_name = sanitize_title($plugin_data['Name']); + $plugin_dist_file = $plugin_dist_name . '.zip'; + + $this->say('Publishing version: ' . $plugin_version); + + // Sanity checks + if(!is_readable($plugin_dist_file)) { + $this->say("Failed to access " . $plugin_dist_file); + return; + } elseif(!file_exists($svn_dir . "/.svn/")) { + $this->say("$svn_dir/.svn/ dir not found, is it a SVN repository?"); + return; + } elseif(file_exists($svn_dir . "/tags/" . $plugin_version)) { + $this->say("A SVN tag already exists: " . $plugin_version); + return; + } + + $collection = $this->collection(); + + // Clean up tmp dirs if the previous run was halted + if(file_exists("$svn_dir/trunk_new") || file_exists("$svn_dir/trunk_old")) { + $this->taskFileSystemStack() + ->stopOnFail() + ->remove(array("$svn_dir/trunk_new", "$svn_dir/trunk_old")) + ->addToCollection($collection); + } + + // Extract the distributable zip to tmp trunk dir + $this->taskExtract($plugin_dist_file) + ->to("$svn_dir/trunk_new") + ->preserveTopDirectory(false) + ->addToCollection($collection); + + // Rename current trunk + if(file_exists("$svn_dir/trunk")) { + $this->taskFileSystemStack() + ->rename("$svn_dir/trunk", "$svn_dir/trunk_old") + ->addToCollection($collection); + } + + // Replace old trunk with a new one + $this->taskFileSystemStack() + ->stopOnFail() + ->rename("$svn_dir/trunk_new", "$svn_dir/trunk") + ->remove("$svn_dir/trunk_old") + ->addToCollection($collection); + + // Mac OS X compatibility issue + $xargsFlag = (stripos(PHP_OS, 'Darwin') !== false) ? '' : '-r'; + + $this->taskExecStack() + ->stopOnFail() + // Set SVN repo as working directory + ->dir($svn_dir) + // Remove files from SVN repo that have already been removed locally + ->exec("svn st | grep ^! | awk '{print \" --force \"$2}' | xargs " . $xargsFlag . " svn rm") + // Recursively add files to SVN that haven't been added yet + ->exec("svn add --force * --auto-props --parents --depth infinity -q") + // Tag the release + ->exec("svn cp trunk tags/$plugin_version") + ->addToCollection($collection); + + $result = $collection->run(); + + if($result->wasSuccessful()) { + // Run or suggest release command depending on a flag + $release_cmd = "svn ci -m \"Release $plugin_version\""; + if(!empty($opts['force'])) { + $svn_login = getenv('WP_SVN_USERNAME'); + $svn_password = getenv('WP_SVN_PASSWORD'); + if ($svn_login && $svn_password) { + $release_cmd .= " --username $svn_login --password $svn_password"; + } else { + $release_cmd .= ' --force-interactive'; + } + $result = $this->taskExecStack() + ->stopOnFail() + ->dir($svn_dir) + ->exec($release_cmd) + ->run(); + } else { + $this->yell( + "Go to '$svn_dir' and run '$release_cmd' to publish the release" + ); + } + } + + return $result; + } + protected function loadEnv() { $dotenv = new Dotenv\Dotenv(__DIR__); $dotenv->load(); } + + protected function loadWP() { + $this->loadEnv(); + require_once(getenv('WP_TEST_PATH') . '/wp-load.php'); + } }