Files
piratepoet/RoboFile.php

416 lines
12 KiB
PHP

<?php
class RoboFile extends \Robo\Tasks {
function install() {
return $this->taskExecStack()
->stopOnFail()
->exec('./composer.phar install')
->exec('npm install')
->run();
}
function update() {
$this->say(getenv('WP_TEST_URL'));
return $this->taskExecStack()
->stopOnFail()
->exec('./composer.phar update')
->exec('npm update')
->run();
}
protected function rsearch($folder, $extensions = array()) {
$dir = new RecursiveDirectoryIterator($folder);
$iterator = new RecursiveIteratorIterator($dir);
$pattern = '/^.+\.('.join($extensions, '|').')$/i';
$files = new RegexIterator(
$iterator,
$pattern,
RecursiveRegexIterator::GET_MATCH
);
$list = array();
foreach($files as $file) {
$list[] = $file[0];
}
return $list;
}
function watch() {
$css_files = $this->rsearch('assets/css/src/', array('styl'));
$js_files = $this->rsearch('assets/js/src/', array('js', 'jsx'));
$this->taskWatch()
->monitor($js_files, function() {
$this->compileJs();
})
->monitor($css_files, function() {
$this->compileCss();
})
->run();
}
function watchCss() {
$css_files = $this->rsearch('assets/css/src/', array('styl'));
$this->taskWatch()
->monitor($css_files, function() {
$this->compileCss();
})
->run();
}
function watchJs() {
$this->_exec('./node_modules/webpack/bin/webpack.js --watch');
}
function compileAll($opts = ['env' => null]) {
$collection = $this->collectionBuilder();
$collection->addCode(function() use ($opts) {
return call_user_func(array($this, 'compileJs'), $opts);
});
$collection->addCode(function() use ($opts) {
return call_user_func(array($this, 'compileCss'), $opts);
});
return $collection->run();
}
function compileJs($opts = ['env' => null]) {
$env = ($opts['env']) ?
sprintf('./node_modules/cross-env/dist/bin/cross-env.js NODE_ENV="%s"', $opts['env']) :
null;
return $this->_exec($env . ' ./node_modules/webpack/bin/webpack.js --bail');
}
function compileCss($opts = ['env' => null]) {
// Clean up folder from previous files
array_map('unlink', glob("assets/css/*.*"));
$css_files = array(
'assets/css/src/admin.styl',
'assets/css/src/newsletter_editor/newsletter_editor.styl',
'assets/css/src/public.styl',
'assets/css/src/rtl.styl',
'assets/css/src/importExport.styl'
);
$compilation_result = $this->_exec(join(' ', array(
'./node_modules/stylus/bin/stylus',
'--include ./node_modules',
'--include-css',
'-u nib',
join(' ', $css_files),
'-o assets/css/'
)));
// Create manifest file
$manifest = [];
foreach(glob('assets/css/*.css') as $style) {
// Hash and rename styles if production environment
if($opts['env'] === 'production') {
$hashed_style = sprintf(
'%s.%s.css',
pathinfo($style)['filename'],
substr(md5_file($style), 0, 8)
);
$manifest[basename($style)] = $hashed_style;
rename($style, str_replace(basename($style), $hashed_style, $style));
} else {
$manifest[basename($style)] = basename($style);
}
}
file_put_contents('assets/css/manifest.json', json_encode($manifest, JSON_PRETTY_PRINT));
return $compilation_result;
}
function makepot() {
return $this->_exec('./node_modules/.bin/grunt makepot'.
' --gruntfile='.__DIR__.'/tasks/makepot/makepot.js'.
' --base_path='.__DIR__
);
}
function pushpot() {
return $this->collectionBuilder()
->addCode(array($this, 'txinit'))
->taskExec('tx push -s')
->run();
}
function packtranslations() {
return $this->collectionBuilder()
->addCode(array($this, 'txinit'))
->taskExec('./tasks/pack_translations.sh')
->run();
}
function txinit() {
// Define WP_TRANSIFEX_API_TOKEN env. variable
$this->loadEnv();
return $this->_exec('./tasks/transifex_init.sh');
}
function testUnit($opts=['file' => null, 'xml' => false]) {
$this->loadEnv();
$this->_exec('vendor/bin/codecept build');
$command = 'vendor/bin/codecept run unit -f '.(($opts['file']) ? $opts['file'] : '');
if($opts['xml']) {
$command .= ' --xml';
}
return $this->_exec($command);
}
function testCoverage($opts=['file' => null, 'xml' => false]) {
$this->loadEnv();
$this->_exec('vendor/bin/codecept build');
$command = join(' ', array(
'vendor/bin/codecept run',
(($opts['file']) ? $opts['file'] : ''),
'--coverage',
($opts['xml']) ? '--coverage-xml' : '--coverage-html'
));
if($opts['xml']) {
$command .= ' --xml';
}
return $this->_exec($command);
}
function testJavascript($xml_output_file = null) {
$this->compileJs();
$command = join(' ', array(
'./node_modules/.bin/mocha',
'-r tests/javascript/mochaTestHelper.js',
'tests/javascript/testBundles/**/*.js'
));
if(!empty($xml_output_file)) {
$command .= sprintf(
' --reporter xunit --reporter-options output="%s"',
$xml_output_file
);
}
return $this->_exec($command);
}
function testDebug() {
$this->_exec('vendor/bin/codecept build');
$this->loadEnv();
return $this->_exec('vendor/bin/codecept run unit --debug');
}
function testFailed() {
$this->loadEnv();
$this->_exec('vendor/bin/codecept build');
return $this->_exec('vendor/bin/codecept run -g failed');
}
function qa() {
$collection = $this->collectionBuilder();
$collection->addCode(array($this, 'qaLint'));
$collection->addCode(function() {
return $this->qaCodeSniffer('all');
});
$collection->addCode(array($this, 'qaLintJavascript'));
return $collection->run();
}
function qaLint() {
return $this->_exec('./tasks/php_lint.sh lib/ tests/ mailpoet.php');
}
function qaLintJavascript() {
return $this->_exec('npm run lint');
}
function qaCodeSniffer($severity='errors') {
if ($severity === 'all') {
$severityFlag = '-w';
} else {
$severityFlag = '-n';
}
return $this->collectionBuilder()
->taskExec(
'./vendor/bin/phpcs '.
'--standard=./tasks/code_sniffer/MailPoet '.
'--ignore=./lib/Util/Sudzy/*,./lib/Util/CSS.php,./lib/Util/XLSXWriter.php,'.
'./lib/Util/pQuery/*,./lib/Config/PopulatorData/Templates/* '.
'lib/ '.
$severityFlag
)
->taskExec(
'./vendor/bin/phpcs '.
'--standard=./tasks/code_sniffer/MailPoetTests '.
'--ignore=./tests/unit/_bootstrap.php '.
'tests/unit/ '.
$severityFlag
)
->run();
}
function svnCheckout() {
$svn_dir = ".mp_svn";
$collection = $this->collectionBuilder();
// Clean up the SVN dir for faster shallow checkout
if(file_exists($svn_dir)) {
$collection->taskExecStack()
->exec('rm -rf ' . $svn_dir);
}
$collection->taskFileSystemStack()
->mkdir($svn_dir);
return $collection->taskExecStack()
->stopOnFail()
->dir($svn_dir)
->exec('svn co https://plugins.svn.wordpress.org/mailpoet/ -N .')
->exec('svn up trunk')
->exec('svn up assets')
->run();
}
function svnPublish($opts = ['force' => false]) {
$this->loadWPFunctions();
$svn_dir = ".mp_svn";
$plugin_data = get_plugin_data('mailpoet.php', false, false);
$plugin_version = $plugin_data['Version'];
$plugin_dist_name = sanitize_title_with_dashes($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->collectionBuilder();
// Clean up tmp dirs if the previous run was halted
if(file_exists("$svn_dir/trunk_new") || file_exists("$svn_dir/trunk_old")) {
$collection->taskFileSystemStack()
->stopOnFail()
->remove(array("$svn_dir/trunk_new", "$svn_dir/trunk_old"));
}
// Extract the distributable zip to tmp trunk dir
$collection->taskExtract($plugin_dist_file)
->to("$svn_dir/trunk_new")
->preserveTopDirectory(false);
// Rename current trunk
if(file_exists("$svn_dir/trunk")) {
$collection->taskFileSystemStack()
->rename("$svn_dir/trunk", "$svn_dir/trunk_old");
}
// Replace old trunk with a new one
$collection->taskFileSystemStack()
->stopOnFail()
->rename("$svn_dir/trunk_new", "$svn_dir/trunk")
->remove("$svn_dir/trunk_old");
// Add new repository assets
$collection->taskFileSystemStack()
->mirror('./plugin_repository/assets', "$svn_dir/assets_new");
// Rename current assets folder
if(file_exists("$svn_dir/assets")) {
$collection->taskFileSystemStack()
->rename("$svn_dir/assets", "$svn_dir/assets_old");
}
// Replace old assets with new ones
$collection->taskFileSystemStack()
->stopOnFail()
->rename("$svn_dir/assets_new", "$svn_dir/assets")
->remove("$svn_dir/assets_old");
// Windows compatibility
$awkCmd = '{print " --force \""$2"\""}';
// Mac OS X compatibility
$xargsFlag = (stripos(PHP_OS, 'Darwin') !== false) ? '' : '-r';
$collection->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 '$awkCmd' | 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");
$result = $collection->run();
if($result->wasSuccessful()) {
// Run or suggest release command depending on a flag
$repo_url = "https://plugins.svn.wordpress.org/$plugin_dist_name";
$release_cmd = "svn ci -m \"Release $plugin_version\"";
$tag_cmd = "svn copy $repo_url/trunk $repo_url/tags/$plugin_version -m \"Tag $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)
->exec($tag_cmd)
->run();
} else {
$this->yell(
"Go to '$svn_dir' and run '$release_cmd' to publish the release"
);
$this->yell(
"Run '$tag_cmd' to tag the release"
);
}
}
return $result;
}
public function publish($opts = ['force' => false]) {
return $this->collectionBuilder()
->addCode(array($this, 'pushpot'))
->addCode(function () use ($opts) {
return $this->svnPublish($opts);
})
->run();
}
protected function loadEnv() {
$dotenv = new Dotenv\Dotenv(__DIR__);
$dotenv->load();
}
protected function loadWPFunctions() {
$this->loadEnv();
define('ABSPATH', getenv('WP_TEST_PATH') . '/');
define('WPINC', 'wp-includes');
require_once(ABSPATH . WPINC . '/functions.php');
require_once(ABSPATH . WPINC . '/formatting.php');
require_once(ABSPATH . WPINC . '/plugin.php');
require_once(ABSPATH . 'wp-admin/includes/plugin.php');
}
}