mirror of
https://github.com/hauke68/Magallanes.git
synced 2025-08-25 21:00:18 +02:00
Compare commits
No commits in common. "master" and "1.0.0" have entirely different histories.
15
.gitignore
vendored
15
.gitignore
vendored
@ -1,4 +1,11 @@
|
|||||||
/vendor/
|
.settings
|
||||||
/build
|
.settings/*
|
||||||
composer.lock
|
.project
|
||||||
.mage.yml
|
.buildpath
|
||||||
|
|
||||||
|
# OS generated files # // GitHub Recommendation
|
||||||
|
######################
|
||||||
|
.DS_Store*
|
||||||
|
ehthumbs.db
|
||||||
|
Icon?
|
||||||
|
Thumbs.db
|
20
.travis.yml
20
.travis.yml
@ -1,20 +0,0 @@
|
|||||||
language: php
|
|
||||||
php:
|
|
||||||
- '7.2'
|
|
||||||
- '7.3'
|
|
||||||
- '7.4'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
fast_finish: true
|
|
||||||
allow_failures:
|
|
||||||
- php: 7.1
|
|
||||||
|
|
||||||
install:
|
|
||||||
- composer install
|
|
||||||
|
|
||||||
script:
|
|
||||||
- mkdir -p build/logs
|
|
||||||
- vendor/bin/phpunit --coverage-clover build/logs/coverage.xml
|
|
||||||
|
|
||||||
after_script:
|
|
||||||
- vendor/bin/coveralls -v --coverage_clover build/logs/coverage.xml
|
|
@ -1,9 +0,0 @@
|
|||||||
CHANGELOG for 4.X
|
|
||||||
=================
|
|
||||||
|
|
||||||
* 4.0.0 (2018-04-02)
|
|
||||||
* v4 series release
|
|
||||||
* Refactored for Symfony 4 and PHP 7.1
|
|
||||||
* Symfony Pool Clear task added
|
|
||||||
* Symfony Pool Prune task added
|
|
||||||
* Symfony Assetic task removed
|
|
@ -1,70 +0,0 @@
|
|||||||
Contributor Guidelines for Magallanes
|
|
||||||
=====================================
|
|
||||||
Welcome to Magallanes! We are much appreciated you've decided to contribute to this project!
|
|
||||||
Please read the following guidelines to make your and our work easier and cleaner.
|
|
||||||
|
|
||||||
**TL;DR**
|
|
||||||
|
|
||||||
1. Write clean code with no mess left
|
|
||||||
2. Contribute the docs when adding configurable new feature
|
|
||||||
3. Create your pull request from `nostromo` branch
|
|
||||||
4. Ensure your code is fully covered by tests
|
|
||||||
|
|
||||||
----------
|
|
||||||
|
|
||||||
# Reporting Issues
|
|
||||||
If you have a problem or you've noticed a bug, please feel free to open a new issue. However follow the rules below:
|
|
||||||
* First, make sure that similar/the same issue doesn't already exists
|
|
||||||
* If you've already found the solution of the problem you are about to report, please feel free to open a new Pull Request. Then follow the rules below in **Developing Magallanes** section.
|
|
||||||
* If you are able to, include some test cases or steps to reproduce the bug for us to examine the problem and find a solution.
|
|
||||||
|
|
||||||
## Opening Pull Requests
|
|
||||||
Pull Request is a very powerful tool, so let's be measured in its usage. Always commit code which has at least 95% of coverage, and if it's a new feature always provide concrete tests.
|
|
||||||
In order to have the PRs prioritized name them with the following tags.
|
|
||||||
|
|
||||||
```
|
|
||||||
[#66] Add new CONTRIBUTING document
|
|
||||||
[FIX] Set correct permissions on deploy stage
|
|
||||||
[FEATURE] Create new PermissionsTask
|
|
||||||
[HOTFIX] Exception not caught on deployment
|
|
||||||
```
|
|
||||||
All Pull Requests must be done to the `nostromo` branch, only exception are Hotfixes.
|
|
||||||
Remember of square brackets when adding issue number. If you'd forget adding them, your whole message will be a comment!
|
|
||||||
|
|
||||||
# Developing Magallanes
|
|
||||||
## Branches
|
|
||||||
The flow is pretty simple.
|
|
||||||
In most common cases we work on the `nostromo` branch. It's the branch with the main development for the current major version. All Pull Requests must merge with that branch. The `master` branch is used to move the validated code and generate the releases in an orderly fashion, also we could use it for hotfixes.
|
|
||||||
|
|
||||||
If you want to use developing branch in your code, simple pass `dev-nostromo` to dependency version in your `composer.json` file:
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"require": {
|
|
||||||
"andres-montanez/magallanes": "dev-nostromo"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Organization and code quality
|
|
||||||
We use [PSR2](http://www.php-fig.org/psr/psr-2/) as PHP coding standard.
|
|
||||||
|
|
||||||
### Tools you can use to ensure your code quality
|
|
||||||
|
|
||||||
1. PHP-CodeSniffer
|
|
||||||
2. [PHP Mess Detector](https://phpmd.org/)
|
|
||||||
3. PHP Copy/Paste Detector
|
|
||||||
4. PHP Dead Code Detector
|
|
||||||
5. [PHP Coding Standards Fixer](http://cs.sensiolabs.org) with --level=psr2
|
|
||||||
|
|
||||||
## Testing and quality
|
|
||||||
We use PHPUnit to test our code. Most of the project is covered with tests, so if you want your code to be merged push it with proper testing and coverage (at least 95%). To execute the tests with code coverage report:
|
|
||||||
```
|
|
||||||
vendor/bin/phpunit --coverage-clover build/logs/coverage.xml
|
|
||||||
vendor/bin/coveralls -v --coverage_clover build/logs/coverage.xml
|
|
||||||
```
|
|
||||||
|
|
||||||
Tests structure follow almost the same structure as production code with `Test` suffix in class and file name. Follow the tests already made as guidelines.
|
|
||||||
|
|
||||||
# Last Words
|
|
||||||
Thank you for using Magallanes, and special thanks for making it better. When adding features always have in mind the main goal *Deploy code from A to B, and run some tasks*, and think if the feature is aiming at that.
|
|
||||||
|
|
6
LICENSE
6
LICENSE
@ -1,4 +1,4 @@
|
|||||||
Copyright (c) 2011 - 2017 Andrés Montañez
|
Copyright (c) 2011 - 2013 Andrés Montañez
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any
|
Permission is hereby granted, free of charge, to any
|
||||||
person obtaining a copy of this software and associated
|
person obtaining a copy of this software and associated
|
||||||
@ -21,3 +21,7 @@ OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|||||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||||
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
--------
|
||||||
|
For the Spyc Library License please see: http://code.google.com/p/spyc/
|
||||||
|
--------
|
53
Mage/Autoload.php
Normal file
53
Mage/Autoload.php
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Magallanes custom Autoload for BuiltIn and Userspace Commands and Tasks.
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
class Autoload
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Autoload a Class by it's Class Name
|
||||||
|
* @param string $className
|
||||||
|
*/
|
||||||
|
public static function autoload($className)
|
||||||
|
{
|
||||||
|
$baseDir = dirname(dirname(__FILE__));
|
||||||
|
$classFile = $baseDir . '/' . str_replace(array('_', '\\'), '/', $className . '.php');
|
||||||
|
require_once $classFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a Class can be loaded.
|
||||||
|
* @param string $className
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public static function isLoadable($className)
|
||||||
|
{
|
||||||
|
$baseDir = dirname(dirname(__FILE__));
|
||||||
|
$classFile = $baseDir . '/' . str_replace(array('_', '\\'), '/', $className . '.php');
|
||||||
|
return (file_exists($classFile) && is_readable($classFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a User's Tasks
|
||||||
|
* @param string $taskName
|
||||||
|
*/
|
||||||
|
public static function loadUserTask($taskName)
|
||||||
|
{
|
||||||
|
$classFile = '.mage/tasks/' . ucfirst($taskName) . '.php';
|
||||||
|
require_once $classFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
54
Mage/Command/AbstractCommand.php
Normal file
54
Mage/Command/AbstractCommand.php
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Command;
|
||||||
|
|
||||||
|
use Mage\Config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract Class for a Magallanes Command
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
abstract class AbstractCommand
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Instance of the loaded Configuration.
|
||||||
|
*
|
||||||
|
* @var Mage\Config
|
||||||
|
*/
|
||||||
|
protected $config = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs the Command
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public abstract function run();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the Loaded Configuration.
|
||||||
|
*
|
||||||
|
* @param Config $config
|
||||||
|
*/
|
||||||
|
public function setConfig(Config $config)
|
||||||
|
{
|
||||||
|
$this->config = $config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the Loaded Configuration.
|
||||||
|
*
|
||||||
|
* @return Config
|
||||||
|
*/
|
||||||
|
public function getConfig()
|
||||||
|
{
|
||||||
|
return $this->config;
|
||||||
|
}
|
||||||
|
}
|
102
Mage/Command/BuiltIn/AddCommand.php
Normal file
102
Mage/Command/BuiltIn/AddCommand.php
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Command\BuiltIn;
|
||||||
|
|
||||||
|
use Mage\Command\AbstractCommand;
|
||||||
|
use Mage\Console;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command for Adding elements to the Configuration.
|
||||||
|
* Currently elements allowed to add:
|
||||||
|
* - environments
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
class AddCommand extends AbstractCommand
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Adds new Configuration Elements
|
||||||
|
* @see \Mage\Command\AbstractCommand::run()
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
$subCommand = $this->getConfig()->getArgument(1);
|
||||||
|
|
||||||
|
try {
|
||||||
|
switch ($subCommand) {
|
||||||
|
case 'environment':
|
||||||
|
$this->addEnvironment();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default;
|
||||||
|
throw new Exception('The Type of Add is needed.');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (Exception $exception) {
|
||||||
|
Console::output('<red>' . $exception->getMessage() . '</red>', 1, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an Environment
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
protected function addEnvironment()
|
||||||
|
{
|
||||||
|
$withReleases = $this->getConfig()->getParameter('enableReleases', false);
|
||||||
|
$environmentName = strtolower($this->getConfig()->getParameter('name'));
|
||||||
|
|
||||||
|
if ($environmentName == '') {
|
||||||
|
throw new Exception('You must specify a name for the environment.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$environmentConfigFile = '.mage/config/environment/' . $environmentName . '.yml';
|
||||||
|
|
||||||
|
if (file_exists($environmentConfigFile)) {
|
||||||
|
throw new Exception('The environment already exists.');
|
||||||
|
}
|
||||||
|
|
||||||
|
Console::output('Adding new environment: <dark_gray>' . $environmentName . '</dark_gray>');
|
||||||
|
|
||||||
|
$releasesConfig = 'releases:' . PHP_EOL
|
||||||
|
. ' enabled: true' . PHP_EOL
|
||||||
|
. ' max: 10' . PHP_EOL
|
||||||
|
. ' symlink: current' . PHP_EOL
|
||||||
|
. ' directory: releases' . PHP_EOL;
|
||||||
|
|
||||||
|
$baseConfig = '#' . $environmentName . PHP_EOL
|
||||||
|
. 'deployment:' . PHP_EOL
|
||||||
|
. ' user: dummy' . PHP_EOL
|
||||||
|
. ' from: ./' . PHP_EOL
|
||||||
|
. ' to: /var/www/vhosts/example.com/www' . PHP_EOL
|
||||||
|
. ' excludes:' . PHP_EOL
|
||||||
|
. ($withReleases ? $releasesConfig : '')
|
||||||
|
. 'hosts:' . PHP_EOL
|
||||||
|
. 'tasks:' . PHP_EOL
|
||||||
|
. ' pre-deploy:' . PHP_EOL
|
||||||
|
. ' on-deploy:' . PHP_EOL
|
||||||
|
. ($withReleases ? (' post-release:' . PHP_EOL) : '')
|
||||||
|
. ' post-deploy:' . PHP_EOL;
|
||||||
|
|
||||||
|
$result = file_put_contents($environmentConfigFile, $baseConfig);
|
||||||
|
|
||||||
|
if ($result) {
|
||||||
|
Console::output('<light_green>Success!!</light_green> Environment config file for <dark_gray>' . $environmentName . '</dark_gray> created successfully at <blue>' . $environmentConfigFile . '</blue>');
|
||||||
|
Console::output('<dark_gray>So please! Review and adjust its configuration.</dark_gray>', 2, 2);
|
||||||
|
} else {
|
||||||
|
Console::output('<light_red>Error!!</light_red> Unable to create config file for environment called <dark_gray>' . $environmentName . '</dark_gray>', 1, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
41
Mage/Command/BuiltIn/CompileCommand.php
Normal file
41
Mage/Command/BuiltIn/CompileCommand.php
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Command\BuiltIn;
|
||||||
|
|
||||||
|
use Mage\Command\AbstractCommand;
|
||||||
|
use Mage\Console;
|
||||||
|
use Mage\Compiler;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command for Compile Magallanes into a PHAR executable
|
||||||
|
*
|
||||||
|
* @author Ismael Ambrosi<ismaambrosi@gmail.com>
|
||||||
|
*/
|
||||||
|
class CompileCommand extends AbstractCommand
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @see \Mage\Compile::compile()
|
||||||
|
*/
|
||||||
|
public function run ()
|
||||||
|
{
|
||||||
|
if (ini_get('phar.readonly')) {
|
||||||
|
Console::output('The <purple>php.ini</purple> variable <light_red>phar.readonly</light_red> must be <yellow>Off</yellow>.', 1, 2);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$compiler = new Compiler;
|
||||||
|
$compiler->compile();
|
||||||
|
|
||||||
|
Console::output('<light_purple>mage.phar</light_purple> compiled <light_green>successfully</light_green>', 0, 2);
|
||||||
|
}
|
||||||
|
}
|
539
Mage/Command/BuiltIn/DeployCommand.php
Normal file
539
Mage/Command/BuiltIn/DeployCommand.php
Normal file
@ -0,0 +1,539 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Command\BuiltIn;
|
||||||
|
|
||||||
|
use Mage\Command\AbstractCommand;
|
||||||
|
use Mage\Command\RequiresEnvironment;
|
||||||
|
use Mage\Task\Factory;
|
||||||
|
use Mage\Task\AbstractTask;
|
||||||
|
use Mage\Task\Releases\SkipOnOverride;
|
||||||
|
use Mage\Task\ErrorWithMessageException;
|
||||||
|
use Mage\Task\SkipException;
|
||||||
|
use Mage\Console;
|
||||||
|
use Mage\Config;
|
||||||
|
use Mage\Mailer;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command for Deploying
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
class DeployCommand extends AbstractCommand implements RequiresEnvironment
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Deploy has Failed
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const FAILED = 'failed';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deploy has Succeded
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const SUCCEDED = 'succeded';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deploy is in progress
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const IN_PROGRESS = 'in_progress';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Time the Deployment has Started
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $startTime = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Time the Deployment has Started to the current Host
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $startTimeHosts = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Time the Deployment to the Hosts has Finished
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $endTimeHosts = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Quantity of Hosts to Deploy to.
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $hostsCount = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Current Status of the Deployment (in progress, succeded, failed)
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected static $deployStatus = 'in_progress';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Total of Failed tasks
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected static $failedTasks = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Status of the Deployment
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function getStatus()
|
||||||
|
{
|
||||||
|
return self::$deployStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deploys the Application
|
||||||
|
* @see \Mage\Command\AbstractCommand::run()
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
// Check if Environment is not Locked
|
||||||
|
$lockFile = '.mage/' . $this->getConfig()->getEnvironment() . '.lock';
|
||||||
|
if (file_exists($lockFile)) {
|
||||||
|
Console::output('<red>This environment is locked!</red>', 1, 2);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for running instance and Lock
|
||||||
|
if (file_exists('.mage/~working.lock')) {
|
||||||
|
Console::output('<red>There is already an instance of Magallanes running!</red>', 1, 2);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
touch('.mage/~working.lock');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release ID
|
||||||
|
$this->getConfig()->setReleaseId(date('YmdHis'));
|
||||||
|
|
||||||
|
// Deploy Summary
|
||||||
|
Console::output('<dark_gray>Deploy summary</dark_gray>', 1, 1);
|
||||||
|
|
||||||
|
// Deploy Summary - Environment
|
||||||
|
Console::output('<dark_gray>Environment:</dark_gray> <purple>' . $this->getConfig()->getEnvironment() . '</purple>', 2, 1);
|
||||||
|
|
||||||
|
// Deploy Summary - Releases
|
||||||
|
if ($this->getConfig()->release('enabled', false)) {
|
||||||
|
Console::output('<dark_gray>Release ID:</dark_gray> <purple>' . $this->getConfig()->getReleaseId() . '</purple>', 2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deploy Summary - SCM
|
||||||
|
if ($this->getConfig()->deployment('scm', false)) {
|
||||||
|
$scmConfig = $this->getConfig()->deployment('scm');
|
||||||
|
if (isset($scmConfig['branch'])) {
|
||||||
|
Console::output('<dark_gray>SCM Branch:</dark_gray> <purple>' . $scmConfig['branch'] . '</purple>', 2, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deploy Summary - Separator Line
|
||||||
|
Console::output('', 0, 1);
|
||||||
|
|
||||||
|
$this->startTime = time();
|
||||||
|
|
||||||
|
// Run Pre-Deployment Tasks
|
||||||
|
$this->runNonDeploymentTasks(AbstractTask::STAGE_PRE_DEPLOY, $this->getConfig(), 'Pre-Deployment');
|
||||||
|
|
||||||
|
// Check Status
|
||||||
|
if (self::$failedTasks > 0) {
|
||||||
|
self::$deployStatus = self::FAILED;
|
||||||
|
Console::output('A total of <dark_gray>' . self::$failedTasks . '</dark_gray> deployment tasks failed: <red>ABORTING</red>', 1, 2);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Run Deployment Tasks
|
||||||
|
$this->runDeploymentTasks();
|
||||||
|
|
||||||
|
// Check Status
|
||||||
|
if (self::$failedTasks > 0) {
|
||||||
|
self::$deployStatus = self::FAILED;
|
||||||
|
Console::output('A total of <dark_gray>' . self::$failedTasks . '</dark_gray> deployment tasks failed: <red>ABORTING</red>', 1, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run Post-Deployment Tasks
|
||||||
|
$this->runNonDeploymentTasks(AbstractTask::STAGE_POST_DEPLOY, $this->getConfig(), 'Post-Deployment');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time Information Hosts
|
||||||
|
if ($this->hostsCount > 0) {
|
||||||
|
$timeTextHost = $this->transcurredTime($this->endTimeHosts - $this->startTimeHosts);
|
||||||
|
Console::output('Time for deployment: <dark_gray>' . $timeTextHost . '</dark_gray>.');
|
||||||
|
|
||||||
|
$timeTextPerHost = $this->transcurredTime(round(($this->endTimeHosts - $this->startTimeHosts) / $this->hostsCount));
|
||||||
|
Console::output('Average time per host: <dark_gray>' . $timeTextPerHost . '</dark_gray>.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time Information General
|
||||||
|
$timeText = $this->transcurredTime(time() - $this->startTime);
|
||||||
|
Console::output('Total time: <dark_gray>' . $timeText . '</dark_gray>.', 1, 2);
|
||||||
|
|
||||||
|
// Send Notifications
|
||||||
|
$this->sendNotification(self::$failedTasks > 0 ? false : true);
|
||||||
|
|
||||||
|
// Unlock
|
||||||
|
if (file_exists('.mage/~working.lock')) {
|
||||||
|
unlink('.mage/~working.lock');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute Pre and Post Deployment Tasks
|
||||||
|
*
|
||||||
|
* @param string $stage
|
||||||
|
* @param Config $config
|
||||||
|
* @param string $title
|
||||||
|
*/
|
||||||
|
protected function runNonDeploymentTasks($stage, Config $config, $title)
|
||||||
|
{
|
||||||
|
$tasksToRun = $config->getTasks($stage);
|
||||||
|
self::$failedTasks = 0;
|
||||||
|
|
||||||
|
// PreDeployment Hook
|
||||||
|
if ($stage == AbstractTask::STAGE_PRE_DEPLOY) {
|
||||||
|
// Look for Remote Source
|
||||||
|
if (is_array($config->deployment('source', null))) {
|
||||||
|
array_unshift($tasksToRun, 'scm/clone');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change Branch
|
||||||
|
if ($config->deployment('scm', false)) {
|
||||||
|
array_unshift($tasksToRun, 'scm/change-branch');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostDeployment Hook
|
||||||
|
if ($stage == AbstractTask::STAGE_POST_DEPLOY) {
|
||||||
|
// If Deploy failed, clear post deploy tasks
|
||||||
|
if (self::$deployStatus == self::FAILED) {
|
||||||
|
$tasksToRun = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change Branch Back
|
||||||
|
if ($config->deployment('scm', false)) {
|
||||||
|
array_unshift($tasksToRun, 'scm/change-branch');
|
||||||
|
$config->addParameter('_changeBranchRevert');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove Remote Source
|
||||||
|
if (is_array($config->deployment('source', null))) {
|
||||||
|
array_push($tasksToRun, 'scm/remove-clone');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count($tasksToRun) == 0) {
|
||||||
|
Console::output('<dark_gray>No </dark_gray><light_cyan>' . $title . '</light_cyan> <dark_gray>tasks defined.</dark_gray>', 1, 3);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Console::output('Starting <dark_gray>' . $title . '</dark_gray> tasks:');
|
||||||
|
|
||||||
|
$tasks = 0;
|
||||||
|
$completedTasks = 0;
|
||||||
|
|
||||||
|
foreach ($tasksToRun as $taskData) {
|
||||||
|
$tasks++;
|
||||||
|
$task = Factory::get($taskData, $config, false, $stage);
|
||||||
|
|
||||||
|
if ($this->runTask($task)) {
|
||||||
|
$completedTasks++;
|
||||||
|
} else {
|
||||||
|
self::$failedTasks++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($completedTasks == $tasks) {
|
||||||
|
$tasksColor = 'green';
|
||||||
|
} else {
|
||||||
|
$tasksColor = 'red';
|
||||||
|
}
|
||||||
|
|
||||||
|
Console::output('Finished <dark_gray>' . $title . '</dark_gray> tasks: <' . $tasksColor . '>' . $completedTasks . '/' . $tasks . '</' . $tasksColor . '> tasks done.', 1, 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function runDeploymentTasks()
|
||||||
|
{
|
||||||
|
if (self::$deployStatus == self::FAILED) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run Tasks for Deployment
|
||||||
|
$hosts = $this->getConfig()->getHosts();
|
||||||
|
$this->hostsCount = count($hosts);
|
||||||
|
self::$failedTasks = 0;
|
||||||
|
|
||||||
|
if ($this->hostsCount == 0) {
|
||||||
|
Console::output('<light_purple>Warning!</light_purple> <dark_gray>No hosts defined, skipping deployment tasks.</dark_gray>', 1, 3);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$this->startTimeHosts = time();
|
||||||
|
foreach ($hosts as $hostKey => $host) {
|
||||||
|
|
||||||
|
// Check if Host has specific configuration
|
||||||
|
$hostConfig = null;
|
||||||
|
if (is_array($host)) {
|
||||||
|
$hostConfig = $host;
|
||||||
|
$host = $hostKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set Host and Host Specific Config
|
||||||
|
$this->getConfig()->setHost($host);
|
||||||
|
$this->getConfig()->setHostConfig($hostConfig);
|
||||||
|
|
||||||
|
// Prepare Tasks
|
||||||
|
$tasks = 0;
|
||||||
|
$completedTasks = 0;
|
||||||
|
|
||||||
|
Console::output('Deploying to <dark_gray>' . $this->getConfig()->getHost() . '</dark_gray>');
|
||||||
|
|
||||||
|
$tasksToRun = $this->getConfig()->getTasks();
|
||||||
|
|
||||||
|
// Guess a Deploy Strategy
|
||||||
|
switch ($this->getConfig()->deployment('strategy', 'guess')) {
|
||||||
|
case 'disabled':
|
||||||
|
$deployStrategy = 'deployment/strategy/disabled';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'rsync':
|
||||||
|
$deployStrategy = 'deployment/strategy/rsync';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'targz':
|
||||||
|
$deployStrategy = 'deployment/strategy/tar-gz';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'guess':
|
||||||
|
default:
|
||||||
|
if ($this->getConfig()->release('enabled', false) == true) {
|
||||||
|
$deployStrategy = 'deployment/strategy/tar-gz';
|
||||||
|
} else {
|
||||||
|
$deployStrategy = 'deployment/strategy/rsync';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
array_unshift($tasksToRun, $deployStrategy);
|
||||||
|
|
||||||
|
if (count($tasksToRun) == 0) {
|
||||||
|
Console::output('<light_purple>Warning!</light_purple> <dark_gray>No </dark_gray><light_cyan>Deployment</light_cyan> <dark_gray>tasks defined.</dark_gray>', 2);
|
||||||
|
Console::output('Deployment to <dark_gray>' . $host . '</dark_gray> skipped!', 1, 3);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
foreach ($tasksToRun as $taskData) {
|
||||||
|
$tasks++;
|
||||||
|
$task = Factory::get($taskData, $this->getConfig(), false, AbstractTask::STAGE_DEPLOY);
|
||||||
|
|
||||||
|
if ($this->runTask($task)) {
|
||||||
|
$completedTasks++;
|
||||||
|
} else {
|
||||||
|
self::$failedTasks++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($completedTasks == $tasks) {
|
||||||
|
$tasksColor = 'green';
|
||||||
|
} else {
|
||||||
|
$tasksColor = 'red';
|
||||||
|
}
|
||||||
|
|
||||||
|
Console::output('Deployment to <dark_gray>' . $this->getConfig()->getHost() . '</dark_gray> completed: <' . $tasksColor . '>' . $completedTasks . '/' . $tasks . '</' . $tasksColor . '> tasks done.', 1, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset Host Config
|
||||||
|
$this->getConfig()->setHostConfig(null);
|
||||||
|
}
|
||||||
|
$this->endTimeHosts = time();
|
||||||
|
|
||||||
|
if (self::$failedTasks > 0) {
|
||||||
|
self::$deployStatus = self::FAILED;
|
||||||
|
} else {
|
||||||
|
self::$deployStatus = self::SUCCEDED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Releasing
|
||||||
|
if (self::$deployStatus == self::SUCCEDED && $this->getConfig()->release('enabled', false) == true) {
|
||||||
|
// Execute the Releases
|
||||||
|
Console::output('Starting the <dark_gray>Releaseing</dark_gray>');
|
||||||
|
foreach ($hosts as $hostKey => $host) {
|
||||||
|
|
||||||
|
// Check if Host has specific configuration
|
||||||
|
$hostConfig = null;
|
||||||
|
if (is_array($host)) {
|
||||||
|
$hostConfig = $host;
|
||||||
|
$host = $hostKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set Host
|
||||||
|
$this->getConfig()->setHost($host);
|
||||||
|
$this->getConfig()->setHostConfig($hostConfig);
|
||||||
|
|
||||||
|
$task = Factory::get('deployment/release', $this->getConfig(), false, AbstractTask::STAGE_DEPLOY);
|
||||||
|
|
||||||
|
if ($this->runTask($task, 'Releasing on host <purple>' . $host . '</purple> ... ')) {
|
||||||
|
$completedTasks++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset Host Config
|
||||||
|
$this->getConfig()->setHostConfig(null);
|
||||||
|
}
|
||||||
|
Console::output('Finished the <dark_gray>Releaseing</dark_gray>', 1, 3);
|
||||||
|
|
||||||
|
// Execute the Post-Release Tasks
|
||||||
|
foreach ($hosts as $hostKey => $host) {
|
||||||
|
|
||||||
|
// Check if Host has specific configuration
|
||||||
|
$hostConfig = null;
|
||||||
|
if (is_array($host)) {
|
||||||
|
$hostConfig = $host;
|
||||||
|
$host = $hostKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set Host
|
||||||
|
$this->getConfig()->setHost($host);
|
||||||
|
$this->getConfig()->setHostConfig($hostConfig);
|
||||||
|
|
||||||
|
$tasksToRun = $this->getConfig()->getTasks(AbstractTask::STAGE_POST_RELEASE);
|
||||||
|
$tasks = count($tasksToRun);
|
||||||
|
$completedTasks = 0;
|
||||||
|
|
||||||
|
if (count($tasksToRun) > 0) {
|
||||||
|
Console::output('Starting <dark_gray>Post-Release</dark_gray> tasks for <dark_gray>' . $host . '</dark_gray>:');
|
||||||
|
|
||||||
|
foreach ($tasksToRun as $task) {
|
||||||
|
$task = Factory::get($task, $this->getConfig(), false, AbstractTask::STAGE_POST_RELEASE);
|
||||||
|
|
||||||
|
if ($this->runTask($task)) {
|
||||||
|
$completedTasks++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($completedTasks == $tasks) {
|
||||||
|
$tasksColor = 'green';
|
||||||
|
} else {
|
||||||
|
$tasksColor = 'red';
|
||||||
|
}
|
||||||
|
Console::output('Finished <dark_gray>Post-Release</dark_gray> tasks for <dark_gray>' . $host . '</dark_gray>: <' . $tasksColor . '>' . $completedTasks . '/' . $tasks . '</' . $tasksColor . '> tasks done.', 1, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset Host Config
|
||||||
|
$this->getConfig()->setHostConfig(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs a Task
|
||||||
|
*
|
||||||
|
* @param string $task
|
||||||
|
* @param string $title
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
protected function runTask($task, $title = null)
|
||||||
|
{
|
||||||
|
$task->init();
|
||||||
|
|
||||||
|
if ($title == null) {
|
||||||
|
$title = 'Running <purple>' . $task->getName() . '</purple> ... ';
|
||||||
|
}
|
||||||
|
Console::output($title, 2, 0);
|
||||||
|
|
||||||
|
$runTask = true;
|
||||||
|
if (($task instanceOf SkipOnOverride) && $this->getConfig()->getParameter('overrideRelease', false)) {
|
||||||
|
$runTask == false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = false;
|
||||||
|
if ($runTask == true) {
|
||||||
|
try {
|
||||||
|
$result = $task->run();
|
||||||
|
|
||||||
|
if ($result == true) {
|
||||||
|
Console::output('<green>OK</green>', 0);
|
||||||
|
$result = true;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Console::output('<red>FAIL</red>', 0);
|
||||||
|
$result = false;
|
||||||
|
}
|
||||||
|
} catch (ErrorWithMessageException $e) {
|
||||||
|
Console::output('<red>FAIL</red> [Message: ' . $e->getMessage() . ']', 0);
|
||||||
|
$result = false;
|
||||||
|
|
||||||
|
} catch (SkipException $e) {
|
||||||
|
Console::output('<yellow>SKIPPED</yellow>', 0);
|
||||||
|
$result = true;
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Console::output('<red>FAIL</red>', 0);
|
||||||
|
$result = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Console::output('<yellow>SKIPPED</yellow>', 0);
|
||||||
|
$result = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Humanize Transcurred time
|
||||||
|
*
|
||||||
|
* @param integer $time
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function transcurredTime($time)
|
||||||
|
{
|
||||||
|
$hours = floor($time / 3600);
|
||||||
|
$minutes = floor(($time - ($hours * 3600)) / 60);
|
||||||
|
$seconds = $time - ($minutes * 60) - ($hours * 3600);
|
||||||
|
$timeText = array();
|
||||||
|
|
||||||
|
if ($hours > 0) {
|
||||||
|
$timeText[] = $hours . ' hours';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($minutes > 0) {
|
||||||
|
$timeText[] = $minutes . ' minutes';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($seconds >= 0) {
|
||||||
|
$timeText[] = $seconds . ' seconds';
|
||||||
|
}
|
||||||
|
|
||||||
|
return implode(' ', $timeText);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send Email Notification if enabled
|
||||||
|
* @param boolean $result
|
||||||
|
*/
|
||||||
|
protected function sendNotification($result)
|
||||||
|
{
|
||||||
|
$projectName = $this->getConfig()->general('name', false);
|
||||||
|
$projectEmail = $this->getConfig()->general('email', false);
|
||||||
|
$notificationsEnabled = $this->getConfig()->general('notifications', false);
|
||||||
|
|
||||||
|
// We need notifications enabled, and a project name and email to send the notification
|
||||||
|
if (!$projectName || !$projectEmail || !$notificationsEnabled) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$mailer = new Mailer;
|
||||||
|
$mailer->setAddress($projectEmail)
|
||||||
|
->setProject($projectName)
|
||||||
|
->setLogFile(Console::getLogFile())
|
||||||
|
->setEnvironment($this->getConfig()->getEnvironment())
|
||||||
|
->send($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
107
Mage/Command/BuiltIn/InitCommand.php
Normal file
107
Mage/Command/BuiltIn/InitCommand.php
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Command\BuiltIn;
|
||||||
|
|
||||||
|
use Mage\Command\AbstractCommand;
|
||||||
|
use Mage\Console;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a Magallanes Configuration into a Proyect
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
class InitCommand extends AbstractCommand
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command for Initalize a new Configuration Proyect
|
||||||
|
* @see \Mage\Command\AbstractCommand::run()
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
$configDir = '.mage';
|
||||||
|
|
||||||
|
Console::output('Initiating managing process for application with <dark_gray>Magallanes</dark_gray>');
|
||||||
|
|
||||||
|
// Check if there is already a config dir
|
||||||
|
if (file_exists($configDir)) {
|
||||||
|
Console::output('<light_red>Error!!</light_red> Already exists <dark_gray>.mage</dark_gray> directory.', 1, 2);
|
||||||
|
} else {
|
||||||
|
$results = array();
|
||||||
|
$results[] = mkdir($configDir);
|
||||||
|
$results[] = mkdir($configDir . '/logs');
|
||||||
|
$results[] = file_put_contents($configDir . '/logs/.gitignore', "*\n!.gitignore");
|
||||||
|
$results[] = mkdir($configDir . '/tasks');
|
||||||
|
$results[] = touch($configDir . '/tasks/.gitignore');
|
||||||
|
$results[] = mkdir($configDir . '/config');
|
||||||
|
$results[] = mkdir($configDir . '/config/environment');
|
||||||
|
$results[] = touch($configDir . '/config/environment/.gitignore');
|
||||||
|
$results[] = file_put_contents($configDir . '/config/general.yml', $this->getGeneralConfig());
|
||||||
|
|
||||||
|
if (!in_array(false, $results)) {
|
||||||
|
Console::output('<light_green>Success!!</light_green> The configuration for <dark_gray>Magallanes</dark_gray> has been generated at <blue>.mage</blue> directory.');
|
||||||
|
Console::output('<dark_gray>Please!! Review and adjust the configuration.</dark_gray>', 2, 2);
|
||||||
|
} else {
|
||||||
|
Console::output('<light_red>Error!!</light_red> Unable to generate the configuration.', 1, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Global Configuration
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function getGeneralConfig()
|
||||||
|
{
|
||||||
|
// Assamble Global Settings
|
||||||
|
$projectName = $this->getConfig()->getParameter('name', '');
|
||||||
|
$notificationEmail = $this->getConfig()->getParameter('email', '');
|
||||||
|
$notificationEnabled = ($notificationEmail != '') ? 'true' : 'false';
|
||||||
|
|
||||||
|
$globalSettings = str_replace(
|
||||||
|
array(
|
||||||
|
'%projectName%',
|
||||||
|
'%notificationEmail%',
|
||||||
|
'%notificationEnabled%',
|
||||||
|
'%loggingEnabled%',
|
||||||
|
'%maxlogs%',
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
$projectName,
|
||||||
|
$notificationEmail,
|
||||||
|
$notificationEnabled,
|
||||||
|
'true',
|
||||||
|
30
|
||||||
|
),
|
||||||
|
$this->getGeneralConfigTemplate()
|
||||||
|
);
|
||||||
|
|
||||||
|
return $globalSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the YAML Template for the Global Configuration
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function getGeneralConfigTemplate()
|
||||||
|
{
|
||||||
|
$template = '# global settings' . PHP_EOL
|
||||||
|
. 'name: %projectName%' . PHP_EOL
|
||||||
|
. 'email: %notificationEmail%' . PHP_EOL
|
||||||
|
. 'notifications: %notificationEnabled%' . PHP_EOL
|
||||||
|
. 'logging: %loggingEnabled%' . PHP_EOL
|
||||||
|
. 'maxlogs: %maxlogs%' . PHP_EOL;
|
||||||
|
|
||||||
|
return $template;
|
||||||
|
}
|
||||||
|
}
|
122
Mage/Command/BuiltIn/InstallCommand.php
Normal file
122
Mage/Command/BuiltIn/InstallCommand.php
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Command\BuiltIn;
|
||||||
|
|
||||||
|
use Mage\Command\AbstractCommand;
|
||||||
|
use Mage\Console;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Installs Magallanes in the Local System
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
class InstallCommand extends AbstractCommand
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Installs Magallanes
|
||||||
|
* @see \Mage\Command\AbstractCommand::run()
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
Console::output('Installing <dark_gray>Magallanes</dark_gray>... ', 1, 0);
|
||||||
|
|
||||||
|
// Vars
|
||||||
|
$installDir = $this->getConfig()->getParameter('installDir', '/opt/magallanes');
|
||||||
|
$systemWide = $this->getConfig()->getParameter('systemWide', false);
|
||||||
|
|
||||||
|
// Clean vars
|
||||||
|
$baseDir = realpath(dirname($installDir));
|
||||||
|
$installDir = basename($installDir);
|
||||||
|
|
||||||
|
// Check if install dir is available
|
||||||
|
if (!is_dir($baseDir) || !is_writable($baseDir)) {
|
||||||
|
Console::output('<red>Failure: install directory is invalid.</red>', 0, 2);
|
||||||
|
|
||||||
|
// Chck if it is a system wide install the user is root
|
||||||
|
} else if ($systemWide && (getenv('LOGNAME') != 'root')) {
|
||||||
|
Console::output('<red>Failure: you have to be root to perform a system wide install.</red>', 0, 2);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$destinationDir = $baseDir . '/' . $installDir;
|
||||||
|
if (!is_dir($destinationDir)) {
|
||||||
|
mkdir($destinationDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy
|
||||||
|
$this->recursiveCopy('./', $destinationDir . '/' . MAGALLANES_VERSION);
|
||||||
|
|
||||||
|
// Check if there is already a symlink
|
||||||
|
if (file_exists($destinationDir . '/' . 'latest')
|
||||||
|
&& is_link($destinationDir . '/' . 'latest')) {
|
||||||
|
unlink($destinationDir . '/' . 'latest');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create "latest" symlink
|
||||||
|
symlink(
|
||||||
|
$destinationDir . '/' . MAGALLANES_VERSION,
|
||||||
|
$destinationDir . '/' . 'latest'
|
||||||
|
);
|
||||||
|
chmod($destinationDir . '/' . MAGALLANES_VERSION . '/bin/mage', 0755);
|
||||||
|
|
||||||
|
if ($systemWide) {
|
||||||
|
if (!file_exists('/usr/bin/mage')) {
|
||||||
|
symlink($destinationDir . '/latest/bin/mage', '/usr/bin/mage');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Console::output('<light_green>Success!</light_green>', 0, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy Files
|
||||||
|
* @param string $from
|
||||||
|
* @param string $to
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
protected function recursiveCopy($from, $to)
|
||||||
|
{
|
||||||
|
if (is_dir($from)) {
|
||||||
|
mkdir($to);
|
||||||
|
$files = scandir($from);
|
||||||
|
|
||||||
|
if (count($files) > 0) {
|
||||||
|
foreach ($files as $file) {
|
||||||
|
if (strpos($file, '.') === 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_dir($from . DIRECTORY_SEPARATOR . $file)) {
|
||||||
|
$this->recursiveCopy(
|
||||||
|
$from . DIRECTORY_SEPARATOR . $file,
|
||||||
|
$to . DIRECTORY_SEPARATOR . $file
|
||||||
|
);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
copy(
|
||||||
|
$from . DIRECTORY_SEPARATOR . $file,
|
||||||
|
$to . DIRECTORY_SEPARATOR . $file
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} elseif (is_file($from)) {
|
||||||
|
return copy($from, $to);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
76
Mage/Command/BuiltIn/ListCommand.php
Normal file
76
Mage/Command/BuiltIn/ListCommand.php
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Command\BuiltIn;
|
||||||
|
|
||||||
|
use Mage\Command\AbstractCommand;
|
||||||
|
use Mage\Console;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds elements to the Configuration.
|
||||||
|
* Currently elements allowed to add:
|
||||||
|
* - environments
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
class ListCommand extends AbstractCommand
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Command for Listing Configuration Elements
|
||||||
|
* @see \Mage\Command\AbstractCommand::run()
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
$subCommand = $this->getConfig()->getArgument(1);
|
||||||
|
|
||||||
|
try {
|
||||||
|
switch ($subCommand) {
|
||||||
|
case 'environments':
|
||||||
|
$this->listEnvironments();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default;
|
||||||
|
throw new Exception('The Type of Elements to List is needed.');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Console::output('<red>' . $e->getMessage() . '</red>', 1, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists the Environments
|
||||||
|
*/
|
||||||
|
protected function listEnvironments()
|
||||||
|
{
|
||||||
|
$environments = array();
|
||||||
|
$content = scandir('.mage/config/environment/');
|
||||||
|
foreach ($content as $file) {
|
||||||
|
if (strpos($file, '.yml') !== false) {
|
||||||
|
$environments[] = str_replace('.yml', '', $file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort($environments);
|
||||||
|
|
||||||
|
if (count($environments) > 0) {
|
||||||
|
Console::output('<dark_gray>These are your configured environments:</dark_gray>', 1, 1);
|
||||||
|
foreach ($environments as $environment) {
|
||||||
|
Console::output('* <light_red>' . $environment . '</light_red>', 2, 1);
|
||||||
|
}
|
||||||
|
Console::output('', 1, 1);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Console::output('<dark_gray>You don\'t have any environment configured.</dark_gray>', 1, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
38
Mage/Command/BuiltIn/LockCommand.php
Normal file
38
Mage/Command/BuiltIn/LockCommand.php
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Command\BuiltIn;
|
||||||
|
|
||||||
|
use Mage\Command\AbstractCommand;
|
||||||
|
use Mage\Command\RequiresEnvironment;
|
||||||
|
use Mage\Console;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command for Locking the Deployment to an Environment
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
class LockCommand extends AbstractCommand implements RequiresEnvironment
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Locks the Deployment to a Environment
|
||||||
|
* @see \Mage\Command\AbstractCommand::run()
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
$lockFile = '.mage/' . $this->getConfig()->getEnvironment() . '.lock';
|
||||||
|
file_put_contents($lockFile, 'Locked environment at date: ' . date('Y-m-d H:i:s'));
|
||||||
|
|
||||||
|
Console::output('Locked deployment to <light_purple>' . $this->getConfig()->getEnvironment() . '</light_purple> environment', 1, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
70
Mage/Command/BuiltIn/ReleasesCommand.php
Normal file
70
Mage/Command/BuiltIn/ReleasesCommand.php
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Command\BuiltIn;
|
||||||
|
|
||||||
|
use Mage\Command\AbstractCommand;
|
||||||
|
use Mage\Command\RequiresEnvironment;
|
||||||
|
use Mage\Task\Factory;
|
||||||
|
use Mage\Console;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command for Managing the Releases
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
class ReleasesCommand extends AbstractCommand implements RequiresEnvironment
|
||||||
|
{
|
||||||
|
private $release = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List the Releases, Rollback to a Release
|
||||||
|
* @see \Mage\Command\AbstractCommand::run()
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
$subcommand = $this->getConfig()->getArgument(1);
|
||||||
|
$lockFile = '.mage/' . $this->getConfig()->getEnvironment() . '.lock';
|
||||||
|
if (file_exists($lockFile) && ($subcommand == 'rollback')) {
|
||||||
|
Console::output('<red>This environment is locked!</red>', 1, 2);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run Tasks for Deployment
|
||||||
|
$hosts = $this->getConfig()->getHosts();
|
||||||
|
|
||||||
|
if (count($hosts) == 0) {
|
||||||
|
Console::output('<light_purple>Warning!</light_purple> <dark_gray>No hosts defined, unable to get releases.</dark_gray>', 1, 3);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
foreach ($hosts as $host) {
|
||||||
|
$this->getConfig()->setHost($host);
|
||||||
|
|
||||||
|
switch ($subcommand) {
|
||||||
|
case 'list':
|
||||||
|
$task = Factory::get('releases/list', $this->getConfig());
|
||||||
|
$task->init();
|
||||||
|
$result = $task->run();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'rollback':
|
||||||
|
$releaseId = $this->getConfig()->getParameter('release', '');
|
||||||
|
$task = Factory::get('releases/rollback', $this->getConfig());
|
||||||
|
$task->init();
|
||||||
|
$task->setRelease($releaseId);
|
||||||
|
$result = $task->run();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
41
Mage/Command/BuiltIn/UnlockCommand.php
Normal file
41
Mage/Command/BuiltIn/UnlockCommand.php
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Command\BuiltIn;
|
||||||
|
|
||||||
|
use Mage\Command\AbstractCommand;
|
||||||
|
use Mage\Command\RequiresEnvironment;
|
||||||
|
use Mage\Console;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command for Unlocking an Environment
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
class UnlockCommand
|
||||||
|
extends AbstractCommand implements RequiresEnvironment
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Unlocks an Environment
|
||||||
|
* @see \Mage\Command\AbstractCommand::run()
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
$lockFile = '.mage/' . $this->getConfig()->getEnvironment() . '.lock';
|
||||||
|
if (file_exists($lockFile)) {
|
||||||
|
@unlink($lockFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
Console::output('Unlocked deployment to <light_purple>' . $this->getConfig()->getEnvironment() . '</light_purple> environment', 1, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
45
Mage/Command/BuiltIn/UpdateCommand.php
Normal file
45
Mage/Command/BuiltIn/UpdateCommand.php
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Command\BuiltIn;
|
||||||
|
|
||||||
|
use Mage\Command\AbstractCommand;
|
||||||
|
use Mage\Task\Factory;
|
||||||
|
use Mage\Console;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the SCM Base Code
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
class UpdateCommand extends AbstractCommand
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Updates the SCM Base Code
|
||||||
|
* @see \Mage\Command\AbstractCommand::run()
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
$task = Factory::get('scm/update', $this->getConfig());
|
||||||
|
$task->init();
|
||||||
|
|
||||||
|
Console::output('Updating application via ' . $task->getName() . ' ... ', 1, 0);
|
||||||
|
$result = $task->run();
|
||||||
|
|
||||||
|
if ($result == true) {
|
||||||
|
Console::output('<green>OK</green>' . PHP_EOL, 0);
|
||||||
|
} else {
|
||||||
|
Console::output('<red>FAIL</red>' . PHP_EOL, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
99
Mage/Command/BuiltIn/UpgradeCommand.php
Normal file
99
Mage/Command/BuiltIn/UpgradeCommand.php
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Command\BuiltIn;
|
||||||
|
|
||||||
|
use Mage\Command\AbstractCommand;
|
||||||
|
use Mage\Console;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Upgrades the Magallanes Version on the Local System
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
class UpgradeCommand extends InstallCommand
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Source for downloading
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const DOWNLOAD = 'http://download.magephp.com/magallanes.{version}.tar.gz';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSON for Upgrade
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const UPGRADE = 'http://download.magephp.com/upgrade.json';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command for Upgrading Magallanes
|
||||||
|
* @see \Mage\Command\BuiltIn\InstallCommand::run()
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
Console::output('Upgrading <dark_gray>Magallanes</dark_gray> ... ', 1, 0);
|
||||||
|
|
||||||
|
$user = '';
|
||||||
|
// Check if user is root
|
||||||
|
Console::executeCommand('whoami', $user);
|
||||||
|
$owner = posix_getpwuid(fileowner(__FILE__));
|
||||||
|
$owner = $owner['name'];
|
||||||
|
|
||||||
|
if ($user != 'root' && $user != $owner) {
|
||||||
|
Console::output('<red>FAIL</red>', 0, 1);
|
||||||
|
Console::output('You need to be the <dark_gray>' . $owner . '</dark_gray> user to perform the upgrade, or <dark_gray>root</dark_gray>.', 2);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Check version
|
||||||
|
$version = json_decode(file_get_contents(self::UPGRADE));
|
||||||
|
|
||||||
|
if ($version !== false) {
|
||||||
|
$versionCompare = version_compare(MAGALLANES_VERSION, $version->latest);
|
||||||
|
if ($versionCompare == 0) {
|
||||||
|
Console::output('<yellow>SKIP</yellow>', 0, 1);
|
||||||
|
Console::output('Your current version is up to date.', 2);
|
||||||
|
|
||||||
|
} else if ($versionCompare == 1) {
|
||||||
|
Console::output('<yellow>SKIP</yellow>', 0, 1);
|
||||||
|
Console::output('Your current version is newer.', 2);
|
||||||
|
|
||||||
|
} else if ($versionCompare == -1) {
|
||||||
|
// Download Package
|
||||||
|
$tarball = file_get_contents(str_replace('{version}', $version->latest, self::DOWNLOAD));
|
||||||
|
if ($tarball === false) {
|
||||||
|
Console::output('<red>FAIL</red>', 0, 1);
|
||||||
|
Console::output('Corrupted download.', 2);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$tarballFile = tempnam('/tmp', 'magallanes_download');
|
||||||
|
rename($tarballFile, $tarballFile . '.tar.gz');
|
||||||
|
$tarballFile .= '.tar.gz';
|
||||||
|
file_put_contents($tarballFile, $tarball);
|
||||||
|
|
||||||
|
Console::executeCommand('rm -rf ' . MAGALLANES_DIRECTORY);
|
||||||
|
Console::executeCommand('cd ' . dirname($tarballFile) . ' && tar xfz ' . $tarballFile);
|
||||||
|
Console::executeCommand('mv ' . dirname($tarballFile) . '/magallanes ' . MAGALLANES_DIRECTORY);
|
||||||
|
|
||||||
|
Console::output('<green>OK</green>', 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Console::output('<red>FAIL</red>', 0, 1);
|
||||||
|
Console::output('Invalid version.', 2);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Console::output('<red>FAIL</red>', 0, 1);
|
||||||
|
Console::output('Invalid version.', 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
34
Mage/Command/BuiltIn/VersionCommand.php
Normal file
34
Mage/Command/BuiltIn/VersionCommand.php
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Command\BuiltIn;
|
||||||
|
|
||||||
|
use Mage\Command\AbstractCommand;
|
||||||
|
use Mage\Console;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command for displaying the Version of Magallanes
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
class VersionCommand extends AbstractCommand
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Display the Magallanes Version
|
||||||
|
* @see \Mage\Command\AbstractCommand::run()
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
Console::output('Running <blue>Magallanes</blue> version <dark_gray>' . MAGALLANES_VERSION .'</dark_gray>', 0, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
54
Mage/Command/Factory.php
Normal file
54
Mage/Command/Factory.php
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Command;
|
||||||
|
|
||||||
|
use Mage\Config;
|
||||||
|
use Mage\Autoload;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a Magallanes Command.
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
class Factory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Gets an instance of a Command.
|
||||||
|
*
|
||||||
|
* @param string $commandName
|
||||||
|
* @param Config $config
|
||||||
|
* @return AbstractCommand
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static function get($commandName, Config $config)
|
||||||
|
{
|
||||||
|
$instance = null;
|
||||||
|
$commandName = ucwords(str_replace('-', ' ', $commandName));
|
||||||
|
$commandName = str_replace(' ', '', $commandName);
|
||||||
|
|
||||||
|
$commandName = str_replace(' ', '_', ucwords(str_replace('/', ' ', $commandName)));
|
||||||
|
$className = 'Mage\\Command\\BuiltIn\\' . $commandName . 'Command';
|
||||||
|
if (Autoload::isLoadable($className)) {
|
||||||
|
$instance = new $className;
|
||||||
|
$instance->setConfig($config);
|
||||||
|
} else {
|
||||||
|
throw new Exception('Command not found.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!($instance instanceOf AbstractCommand)) {
|
||||||
|
throw new Exception('The command ' . $commandName . ' must be an instance of Mage\Command\AbstractCommand.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $instance;
|
||||||
|
}
|
||||||
|
}
|
20
Mage/Command/RequiresEnvironment.php
Normal file
20
Mage/Command/RequiresEnvironment.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Command;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that a Command depends of an Environment.
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
interface RequiresEnvironment
|
||||||
|
{
|
||||||
|
}
|
67
Mage/Compiler.php
Normal file
67
Mage/Compiler.php
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage;
|
||||||
|
|
||||||
|
use Phar;
|
||||||
|
use RecursiveIteratorIterator;
|
||||||
|
use RecursiveDirectoryIterator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compiles the library into a .phar file
|
||||||
|
*
|
||||||
|
* @author Ismael Ambrosi<ismaambrosi@gmail.com>
|
||||||
|
*/
|
||||||
|
class Compiler
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compiles the library
|
||||||
|
*
|
||||||
|
* @param string $file
|
||||||
|
*/
|
||||||
|
public function compile($file = 'mage.phar')
|
||||||
|
{
|
||||||
|
if (file_exists($file)) {
|
||||||
|
unlink($file);
|
||||||
|
}
|
||||||
|
|
||||||
|
$phar = new Phar($file, 0, 'mage.phar');
|
||||||
|
$phar->setSignatureAlgorithm(Phar::SHA1);
|
||||||
|
|
||||||
|
$phar->startBuffering();
|
||||||
|
|
||||||
|
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(__DIR__), RecursiveIteratorIterator::CHILD_FIRST);
|
||||||
|
/** @var $path SplFileInfo */
|
||||||
|
foreach ($iterator as $path) {
|
||||||
|
if ($path->isFile()) {
|
||||||
|
$phar->addFromString(str_replace(dirname(__DIR__).'/', '', $path->getPathname()), file_get_contents($path));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$binary = file(__DIR__.'/../bin/mage');
|
||||||
|
unset($binary[0]);
|
||||||
|
$binary = implode(PHP_EOL, $binary);
|
||||||
|
|
||||||
|
$phar->addFromString('mage', str_replace(
|
||||||
|
'$baseDir = dirname(dirname(__FILE__));',
|
||||||
|
'$baseDir = __DIR__;',
|
||||||
|
$binary
|
||||||
|
));
|
||||||
|
|
||||||
|
$phar->setStub("#!/usr/bin/env php\n<?php Phar::mapPhar('mage.phar'); require 'phar://mage.phar/mage'; __HALT_COMPILER();");
|
||||||
|
|
||||||
|
$phar->stopBuffering();
|
||||||
|
|
||||||
|
unset($phar);
|
||||||
|
|
||||||
|
chmod($file, 0755);
|
||||||
|
}
|
||||||
|
}
|
498
Mage/Config.php
Normal file
498
Mage/Config.php
Normal file
@ -0,0 +1,498 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Magallanes Configuration
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
class Config
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Arguments loaded
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $arguments = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameters loaded
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $parameters = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Environment
|
||||||
|
* @var string|boolean
|
||||||
|
*/
|
||||||
|
private $environment = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current Host
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $host = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom Configuration for the current Host
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $hostConfig = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Relase ID
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
private $releaseId = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Magallanes Global and Environment configuration
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $config = array(
|
||||||
|
'general' => array(),
|
||||||
|
'environment' => array(),
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the Command Line options
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
protected function parse($arguments)
|
||||||
|
{
|
||||||
|
foreach ($arguments as $argument) {
|
||||||
|
if (preg_match('/to:[\w]+/i', $argument)) {
|
||||||
|
$this->environment = str_replace('to:', '', $argument);
|
||||||
|
|
||||||
|
} else if (preg_match('/--[\w]+/i', $argument)) {
|
||||||
|
$optionValue = explode('=', substr($argument, 2));
|
||||||
|
if (count($optionValue) == 1) {
|
||||||
|
$this->parameters[$optionValue[0]] = true;
|
||||||
|
} else if (count($optionValue) == 2) {
|
||||||
|
if (strtolower($optionValue[1]) == 'true') {
|
||||||
|
$this->parameters[$optionValue[0]] = true;
|
||||||
|
} else if (strtolower($optionValue[1]) == 'false') {
|
||||||
|
$this->parameters[$optionValue[0]] = false;
|
||||||
|
} else {
|
||||||
|
$this->parameters[$optionValue[0]] = $optionValue[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$this->arguments[] = $argument;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the General Configuration
|
||||||
|
*/
|
||||||
|
protected function loadGeneral()
|
||||||
|
{
|
||||||
|
if (file_exists('.mage/config/general.yml')) {
|
||||||
|
$this->config['general'] = spyc_load_file('.mage/config/general.yml');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the Environment configuration
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
protected function loadEnvironment()
|
||||||
|
{
|
||||||
|
$environment = $this->getEnvironment();
|
||||||
|
if (($environment != false) && file_exists('.mage/config/environment/' . $environment . '.yml')) {
|
||||||
|
$this->config['environment'] = spyc_load_file('.mage/config/environment/' . $environment . '.yml');
|
||||||
|
|
||||||
|
// Create temporal directory for clone
|
||||||
|
if (isset($this->config['environment']['deployment']['source']) && is_array($this->config['environment']['deployment']['source'])) {
|
||||||
|
if (trim($this->config['environment']['deployment']['source']['temporal']) == '') {
|
||||||
|
$this->config['environment']['deployment']['source']['temporal'] = '/tmp';
|
||||||
|
}
|
||||||
|
$newTemporal = rtrim($this->config['environment']['deployment']['source']['temporal'], '/')
|
||||||
|
. '/' . md5(microtime()) . '/';
|
||||||
|
$this->config['environment']['deployment']['source']['temporal'] = $newTemporal;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} else if (($environment != '') && !file_exists('.mage/config/environment/' . $environment . '.yml')) {
|
||||||
|
throw new Exception('Environment does not exists.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load the Configuration and parses the Arguments
|
||||||
|
*
|
||||||
|
* @param array $arguments
|
||||||
|
*/
|
||||||
|
public function load($arguments)
|
||||||
|
{
|
||||||
|
$this->parse($arguments);
|
||||||
|
$this->loadGeneral();
|
||||||
|
$this->loadEnvironment();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reloads the configuration
|
||||||
|
*/
|
||||||
|
public function reload()
|
||||||
|
{
|
||||||
|
$this->loadGeneral();
|
||||||
|
$this->loadEnvironment();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the invocation argument based on a position
|
||||||
|
* 0 = Invoked Command Name
|
||||||
|
*
|
||||||
|
* @param integer $position
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function getArgument($position = 0)
|
||||||
|
{
|
||||||
|
if (isset($this->arguments[$position])) {
|
||||||
|
return $this->arguments[$position];
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all the invocation arguments
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getArguments()
|
||||||
|
{
|
||||||
|
return $this->arguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the a parameter
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @param mixed $default
|
||||||
|
* @param array $extraParameters
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function getParameter($name, $default = null, $extraParameters = array())
|
||||||
|
{
|
||||||
|
if (isset($this->parameters[$name])) {
|
||||||
|
return $this->parameters[$name];
|
||||||
|
} else if (isset($extraParameters[$name])) {
|
||||||
|
return $extraParameters[$name];
|
||||||
|
} else {
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all the invocation arguments
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getParameters()
|
||||||
|
{
|
||||||
|
return $this->parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds (or replaces) a parameter
|
||||||
|
* @param string $name
|
||||||
|
* @param mixed $value
|
||||||
|
*/
|
||||||
|
public function addParameter($name, $value = true)
|
||||||
|
{
|
||||||
|
$this->parameters[$name] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Current environment
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function getEnvironment()
|
||||||
|
{
|
||||||
|
return $this->environment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the Tasks to execute
|
||||||
|
*
|
||||||
|
* @param string $stage
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getTasks($stage = 'deploy')
|
||||||
|
{
|
||||||
|
if ($stage == 'deploy') {
|
||||||
|
$configStage = 'on-deploy';
|
||||||
|
} else {
|
||||||
|
$configStage = $stage;
|
||||||
|
}
|
||||||
|
|
||||||
|
$tasks = array();
|
||||||
|
$config = $this->getEnvironmentOption('tasks', array());
|
||||||
|
|
||||||
|
// Host Config
|
||||||
|
if (is_array($this->hostConfig) && isset($this->hostConfig['tasks'])) {
|
||||||
|
if (isset($this->hostConfig['tasks'][$configStage])) {
|
||||||
|
$config[$configStage] = $this->hostConfig['tasks'][$configStage];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($config[$configStage])) {
|
||||||
|
$tasksData = ($config[$configStage] ? (array) $config[$configStage] : array());
|
||||||
|
foreach ($tasksData as $taskName => $taskData) {
|
||||||
|
if (is_array($taskData)) {
|
||||||
|
;
|
||||||
|
$tasks[] = array(
|
||||||
|
'name' => key($taskData),
|
||||||
|
'parameters' => current($taskData),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$tasks[] = $taskData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $tasks;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current Hosts to deploy
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getHosts()
|
||||||
|
{
|
||||||
|
$hosts = array();
|
||||||
|
|
||||||
|
if (isset($this->config['environment']['hosts'])) {
|
||||||
|
if (is_array($this->config['environment']['hosts'])) {
|
||||||
|
$hosts = (array) $this->config['environment']['hosts'];
|
||||||
|
} else if (is_string($this->config['environment']['hosts']) && file_exists($this->config['environment']['hosts']) && is_readable($this->config['environment']['hosts'])) {
|
||||||
|
$fileContent = fopen($this->config['environment']['hosts'], 'r');
|
||||||
|
while (($host = fgets($fileContent)) == true) {
|
||||||
|
$host = trim($host);
|
||||||
|
if ($host != '') {
|
||||||
|
$hosts[] = $host;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $hosts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the current host
|
||||||
|
*
|
||||||
|
* @param string $host
|
||||||
|
* @return \Mage\Config
|
||||||
|
*/
|
||||||
|
public function setHost($host)
|
||||||
|
{
|
||||||
|
$this->host = $host;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the host specific configuration
|
||||||
|
*
|
||||||
|
* @param array $hostConfig
|
||||||
|
* @return \Mage\Config
|
||||||
|
*/
|
||||||
|
public function setHostConfig($hostConfig = null)
|
||||||
|
{
|
||||||
|
$this->hostConfig = $hostConfig;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current host name
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getHostName()
|
||||||
|
{
|
||||||
|
$info = explode(':', $this->host);
|
||||||
|
return $info[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current Host Port
|
||||||
|
*
|
||||||
|
* @return integer
|
||||||
|
*/
|
||||||
|
public function getHostPort()
|
||||||
|
{
|
||||||
|
$info = explode(':', $this->host);
|
||||||
|
$info[] = $this->deployment('port', '22');
|
||||||
|
return $info[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current Host
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getHost()
|
||||||
|
{
|
||||||
|
return $this->host;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets General Configuration
|
||||||
|
*
|
||||||
|
* @param string $option
|
||||||
|
* @param string $default
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function general($option, $default = false)
|
||||||
|
{
|
||||||
|
$config = $this->config['general'];
|
||||||
|
if (isset($config[$option])) {
|
||||||
|
if (is_array($default) && ($config[$option] == '')) {
|
||||||
|
return $default;
|
||||||
|
} else {
|
||||||
|
return $config[$option];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets Environments Full Configuration
|
||||||
|
*
|
||||||
|
* @param string $option
|
||||||
|
* @param string $default
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function environmentConfig($option, $default = false)
|
||||||
|
{
|
||||||
|
return $this->getEnvironmentOption($option, $default);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get deployment configuration
|
||||||
|
*
|
||||||
|
* @param string $option
|
||||||
|
* @param string $default
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function deployment($option, $default = false)
|
||||||
|
{
|
||||||
|
// Host Config
|
||||||
|
if (is_array($this->hostConfig) && isset($this->hostConfig['deployment'])) {
|
||||||
|
if (isset($this->hostConfig['deployment'][$option])) {
|
||||||
|
return $this->hostConfig['deployment'][$option];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Global Config
|
||||||
|
$config = $this->getEnvironmentOption('deployment', array());
|
||||||
|
if (isset($config[$option])) {
|
||||||
|
if (is_array($default) && ($config[$option] == '')) {
|
||||||
|
return $default;
|
||||||
|
} else {
|
||||||
|
return $config[$option];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns Releaseing Options
|
||||||
|
*
|
||||||
|
* @param string $option
|
||||||
|
* @param string $default
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function release($option, $default = false)
|
||||||
|
{
|
||||||
|
// Host Config
|
||||||
|
if (is_array($this->hostConfig) && isset($this->hostConfig['releases'])) {
|
||||||
|
if (isset($this->hostConfig['releases'][$option])) {
|
||||||
|
return $this->hostConfig['releases'][$option];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$config = $this->getEnvironmentOption('releases', array());
|
||||||
|
if (isset($config[$option])) {
|
||||||
|
if (is_array($default) && ($config[$option] == '')) {
|
||||||
|
return $default;
|
||||||
|
} else {
|
||||||
|
return $config[$option];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set From Deployment Path
|
||||||
|
*
|
||||||
|
* @param string $from
|
||||||
|
* @return \Mage\Config
|
||||||
|
*/
|
||||||
|
public function setFrom($from)
|
||||||
|
{
|
||||||
|
$this->config['environment']['deployment']['from'] = $from;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the Current Release ID
|
||||||
|
*
|
||||||
|
* @param integer $id
|
||||||
|
* @return \Mage\Config
|
||||||
|
*/
|
||||||
|
public function setReleaseId($id)
|
||||||
|
{
|
||||||
|
$this->releaseId = $id;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the Current Release ID
|
||||||
|
*
|
||||||
|
* @return integer
|
||||||
|
*/
|
||||||
|
public function getReleaseId()
|
||||||
|
{
|
||||||
|
return $this->releaseId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Environment root option
|
||||||
|
*
|
||||||
|
* @param string $option
|
||||||
|
* @param mixed $default
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
protected function getEnvironmentOption($option, $default = array())
|
||||||
|
{
|
||||||
|
$config = $this->config['environment'];
|
||||||
|
if (isset($config[$option])) {
|
||||||
|
return $config[$option];
|
||||||
|
} else {
|
||||||
|
return $default;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
242
Mage/Console.php
Normal file
242
Mage/Console.php
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use RecursiveDirectoryIterator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Magallanes interface between the Tasks and Commands and the User's Console.
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
class Console
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handler to the current Log File.
|
||||||
|
* @var handler
|
||||||
|
*/
|
||||||
|
private static $log = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current logfile
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private static $logFile = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables or Disables Logging
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
|
private static $logEnabled = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* String Buffer for the screen output
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private static $screenBuffer = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Output of executed commands
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private static $commandsOutput = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runns a Magallanes Command
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function run($arguments)
|
||||||
|
{
|
||||||
|
// Declare a Shutdown Closure
|
||||||
|
register_shutdown_function(function() {
|
||||||
|
// Only Unlock if there was an error
|
||||||
|
if (error_get_last() !== null) {
|
||||||
|
if (file_exists('.mage/~working.lock')) {
|
||||||
|
unlink('.mage/~working.lock');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Load configuration
|
||||||
|
$configError = false;
|
||||||
|
try {
|
||||||
|
// Load Config
|
||||||
|
$config = new Config;
|
||||||
|
$config->load($arguments);
|
||||||
|
$configLoadedOk = true;
|
||||||
|
|
||||||
|
} catch (Exception $exception) {
|
||||||
|
$configError = $exception->getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Command Option
|
||||||
|
$commandName = $config->getArgument(0);
|
||||||
|
|
||||||
|
// Logging
|
||||||
|
$showGrettings = true;
|
||||||
|
if (in_array($commandName, array('install', 'upgrade', 'version'))) {
|
||||||
|
self::$logEnabled = false;
|
||||||
|
$showGrettings = false;
|
||||||
|
} else {
|
||||||
|
self::$logEnabled = $config->general('logging', false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grettings
|
||||||
|
if ($showGrettings) {
|
||||||
|
self::output('Starting <blue>Magallanes</blue>', 0, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run Command - Check if there is a Configuration Error
|
||||||
|
if ($configError !== false) {
|
||||||
|
self::output('<red>' . $configError . '</red>', 1, 2);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Run Command and check for Command Requirements
|
||||||
|
try {
|
||||||
|
$command = Command\Factory::get($commandName, $config);
|
||||||
|
|
||||||
|
if ($command instanceOf Command\RequiresEnvironment) {
|
||||||
|
if ($config->getEnvironment() == false) {
|
||||||
|
throw new Exception('You must specify an environment for this command.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$command->run();
|
||||||
|
|
||||||
|
} catch (Exception $exception) {
|
||||||
|
self::output('<red>' . $exception->getMessage() . '</red>', 1, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($showGrettings) {
|
||||||
|
self::output('Finished <blue>Magallanes</blue>', 0, 2);
|
||||||
|
if (file_exists('.mage/~working.lock')) {
|
||||||
|
unlink('.mage/~working.lock');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if logs need to be deleted
|
||||||
|
self::checkLogs($config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Outputs a message to the user's screen.
|
||||||
|
*
|
||||||
|
* @param string $message
|
||||||
|
* @param integer $tabs
|
||||||
|
* @param integer $newLine
|
||||||
|
*/
|
||||||
|
public static function output($message, $tabs = 1, $newLine = 1)
|
||||||
|
{
|
||||||
|
self::log(strip_tags($message));
|
||||||
|
|
||||||
|
self::$screenBuffer .= str_repeat("\t", $tabs)
|
||||||
|
. strip_tags($message)
|
||||||
|
. str_repeat(PHP_EOL, $newLine);
|
||||||
|
|
||||||
|
$output = str_repeat("\t", $tabs)
|
||||||
|
. Console\Colors::color($message)
|
||||||
|
. str_repeat(PHP_EOL, $newLine);
|
||||||
|
|
||||||
|
echo $output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes a Command on the Shell
|
||||||
|
*
|
||||||
|
* @param string $command
|
||||||
|
* @param string $output
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public static function executeCommand($command, &$output = null)
|
||||||
|
{
|
||||||
|
self::log('---------------------------------');
|
||||||
|
self::log('---- Executing: $ ' . $command);
|
||||||
|
|
||||||
|
$return = 1;
|
||||||
|
$log = array();
|
||||||
|
exec($command . ' 2>&1', $log, $return);
|
||||||
|
$log = implode(PHP_EOL, $log);
|
||||||
|
|
||||||
|
if (!$return) {
|
||||||
|
$output = trim($log);
|
||||||
|
}
|
||||||
|
self::$commandsOutput .= PHP_EOL . trim($log) . PHP_EOL;
|
||||||
|
|
||||||
|
self::log($log);
|
||||||
|
self::log('---------------------------------');
|
||||||
|
|
||||||
|
return !$return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log a message to the logfile.
|
||||||
|
*
|
||||||
|
* @param string $message
|
||||||
|
* @param boolean $continuation
|
||||||
|
*/
|
||||||
|
public static function log($message, $continuation = false)
|
||||||
|
{
|
||||||
|
if (self::$logEnabled) {
|
||||||
|
if (self::$log == null) {
|
||||||
|
self::$logFile = realpath('.mage/logs') . '/log-' . date('Ymd-His') . '.log';
|
||||||
|
self::$log = fopen(self::$logFile, 'w');
|
||||||
|
}
|
||||||
|
|
||||||
|
$message = date('Y-m-d H:i:s -- ') . $message;
|
||||||
|
fwrite(self::$log, $message . PHP_EOL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the screen buffer
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function getOutput()
|
||||||
|
{
|
||||||
|
return self::$screenBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Log File
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function getLogFile()
|
||||||
|
{
|
||||||
|
return self::$logFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check Logs
|
||||||
|
* @param \Mage\Config $config
|
||||||
|
*/
|
||||||
|
private static function checkLogs(Config $config)
|
||||||
|
{
|
||||||
|
if (self::$logEnabled) {
|
||||||
|
$maxLogs = $config->general('maxlogs', 30);
|
||||||
|
|
||||||
|
$logs = array();
|
||||||
|
foreach (new RecursiveDirectoryIterator('.mage/logs', RecursiveDirectoryIterator::SKIP_DOTS) as $log) {
|
||||||
|
if (strpos($log->getFilename(), 'log-') === 0) {
|
||||||
|
$logs[] = $log->getFilename();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sort($logs);
|
||||||
|
if (count($logs) > $maxLogs) {
|
||||||
|
$logsToDelete = array_slice($logs, 0, count($logs) - $maxLogs);
|
||||||
|
foreach ($logsToDelete as $logToDeelte) {
|
||||||
|
unlink('.mage/logs/' . $logToDeelte);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
68
Mage/Console/Colors.php
Normal file
68
Mage/Console/Colors.php
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Console;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the different colors available for the Terminal or Console.
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
class Colors
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* List of Colors and they Terminal/Console representation.
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private static $foregroundColors = array(
|
||||||
|
'black' => '0;30',
|
||||||
|
'dark_gray' => '1;30',
|
||||||
|
'blue' => '0;34',
|
||||||
|
'light_blue' => '1;34',
|
||||||
|
'green' => '0;32',
|
||||||
|
'light_green' => '1;32',
|
||||||
|
'cyan' => '0;36',
|
||||||
|
'light_cyan' => '1;36',
|
||||||
|
'red' => '0;31',
|
||||||
|
'light_red' => '1;31',
|
||||||
|
'purple' => '0;35',
|
||||||
|
'light_purple' => '1;35',
|
||||||
|
'brown' => '0;33',
|
||||||
|
'yellow' => '1;33',
|
||||||
|
'light_gray' => '0;37',
|
||||||
|
'white' => '1;37'
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a Text to represent Colors in the Terminal/Console.
|
||||||
|
*
|
||||||
|
* @param string $string
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function color($string)
|
||||||
|
{
|
||||||
|
foreach (self::$foregroundColors as $key => $code) {
|
||||||
|
$replaceFrom = array(
|
||||||
|
'<' . $key . '>',
|
||||||
|
'</' . $key . '>'
|
||||||
|
);
|
||||||
|
|
||||||
|
$replaceTo = array(
|
||||||
|
"\033[" . $code . 'm',
|
||||||
|
"\033[0m"
|
||||||
|
);
|
||||||
|
|
||||||
|
$string = str_replace($replaceFrom, $replaceTo, $string);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $string;
|
||||||
|
}
|
||||||
|
}
|
92
Mage/Mailer.php
Normal file
92
Mage/Mailer.php
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage;
|
||||||
|
|
||||||
|
use Mage\Console;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mailer Helper.
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
class Mailer
|
||||||
|
{
|
||||||
|
const EOL = "\r\n";
|
||||||
|
const SUBJECT = '[Magallanes] Deployment of {project} to {environment}: {result}';
|
||||||
|
|
||||||
|
protected $address;
|
||||||
|
protected $project;
|
||||||
|
protected $environment;
|
||||||
|
protected $logFile;
|
||||||
|
|
||||||
|
public function setAddress($address)
|
||||||
|
{
|
||||||
|
$this->address = $address;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setProject($project)
|
||||||
|
{
|
||||||
|
$this->project = $project;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setEnvironment($environment)
|
||||||
|
{
|
||||||
|
$this->environment = $environment;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setLogFile($logFile)
|
||||||
|
{
|
||||||
|
$this->logFile = $logFile;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function send($result)
|
||||||
|
{
|
||||||
|
$boundary = md5(date('r', time()));
|
||||||
|
|
||||||
|
$headers = 'From: ' . $this->address
|
||||||
|
. self::EOL
|
||||||
|
. 'Reply-To: ' . $this->address
|
||||||
|
. self::EOL
|
||||||
|
. 'MIME-Version: 1.0'
|
||||||
|
. self::EOL
|
||||||
|
. 'Content-Type: multipart/mixed; boundary=Mage-mixed-' . $boundary;
|
||||||
|
|
||||||
|
$subject = str_replace(
|
||||||
|
array('{project}', '{environment}', '{result}'),
|
||||||
|
array($this->project, $this->environment, $result ? 'SUCCESS' : 'FAILURE'),
|
||||||
|
self::SUBJECT
|
||||||
|
)
|
||||||
|
;
|
||||||
|
$attachment = chunk_split(base64_encode(file_get_contents($this->logFile)));
|
||||||
|
|
||||||
|
$message = 'This is a multi-part message in MIME format.' . self::EOL
|
||||||
|
. '--Mage-mixed-' . $boundary . self::EOL
|
||||||
|
. 'Content-Type: text/plain; charset=iso-8859-1' . self::EOL
|
||||||
|
. 'Content-Transfer-Encoding: quoted-printable' . self::EOL
|
||||||
|
. self::EOL
|
||||||
|
. strip_tags(Console::getOutput()) . self::EOL
|
||||||
|
. self::EOL
|
||||||
|
. '--Mage-mixed-' . $boundary . self::EOL
|
||||||
|
. 'Content-Type: text/plain; name="log.txt"' . self::EOL
|
||||||
|
. 'Content-Transfer-Encoding: base64' . self::EOL
|
||||||
|
. 'Content-Disposition: attachment' . self::EOL
|
||||||
|
. self::EOL
|
||||||
|
. $attachment . self::EOL
|
||||||
|
. '--Mage-mixed-' . $boundary . '--' . self::EOL
|
||||||
|
;
|
||||||
|
|
||||||
|
$mail_sent = @mail($this->address, $subject, $message, $headers);
|
||||||
|
}
|
||||||
|
}
|
216
Mage/Task/AbstractTask.php
Normal file
216
Mage/Task/AbstractTask.php
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Task;
|
||||||
|
|
||||||
|
use Mage\Console;
|
||||||
|
use Mage\Config;
|
||||||
|
use Mage\Task\ErrorWithMessageException;
|
||||||
|
use Mage\Task\SkipException;
|
||||||
|
use Mage\Task\Releases\IsReleaseAware;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract Class for a Magallanes Task
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
abstract class AbstractTask
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Stage Constant for Pre Deployment
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const STAGE_PRE_DEPLOY = 'pre-deploy';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stage Constant for Deployment
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const STAGE_DEPLOY = 'deploy';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stage Constant for Post Deployment
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const STAGE_POST_DEPLOY = 'post-deploy';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stage Constant for Post Release
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const STAGE_POST_RELEASE = 'post-release';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration
|
||||||
|
* @var Config;
|
||||||
|
*/
|
||||||
|
protected $config = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the Task is running in a Rollback
|
||||||
|
* @var boolean
|
||||||
|
*/
|
||||||
|
protected $inRollback = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates the Stage the Task is running ing
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $stage = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extra parameters
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $parameters = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Title of the Task
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public abstract function getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs the task
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
* @throws Exception
|
||||||
|
* @throws ErrorWithMessageException
|
||||||
|
* @throws SkipException
|
||||||
|
*/
|
||||||
|
public abstract function run();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task Constructor
|
||||||
|
*
|
||||||
|
* @param Config $config
|
||||||
|
* @param boolean $inRollback
|
||||||
|
* @param string $stage
|
||||||
|
* @param array $parameters
|
||||||
|
*/
|
||||||
|
public final function __construct(Config $config, $inRollback = false, $stage = null, $parameters = array())
|
||||||
|
{
|
||||||
|
$this->config = $config;
|
||||||
|
$this->inRollback = $inRollback;
|
||||||
|
$this->stage = $stage;
|
||||||
|
$this->parameters = $parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the Task is running in a Rollback operation
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function inRollback()
|
||||||
|
{
|
||||||
|
return $this->inRollback;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the Stage of the Deployment:
|
||||||
|
* - pre-deploy
|
||||||
|
* - deploy
|
||||||
|
* - post-deploy
|
||||||
|
* - post-release
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getStage()
|
||||||
|
{
|
||||||
|
return $this->stage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the Configuration
|
||||||
|
* @return Config;
|
||||||
|
*/
|
||||||
|
public function getConfig()
|
||||||
|
{
|
||||||
|
return $this->config;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the Task, optional to implement
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a Parameter, or a default if not found
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @param mixed $default
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function getParameter($name, $default = null)
|
||||||
|
{
|
||||||
|
return $this->getConfig()->getParameter($name, $default, $this->parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs a Shell Command Localy
|
||||||
|
* @param string $command
|
||||||
|
* @param string $output
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
protected final function runCommandLocal($command, &$output = null)
|
||||||
|
{
|
||||||
|
return Console::executeCommand($command, $output);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs a Shell Command on the Remote Host
|
||||||
|
* @param string $command
|
||||||
|
* @param string $output
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
protected final function runCommandRemote($command, &$output = null)
|
||||||
|
{
|
||||||
|
if ($this->getConfig()->release('enabled', false) == true) {
|
||||||
|
if ($this instanceOf IsReleaseAware) {
|
||||||
|
$releasesDirectory = '';
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$releasesDirectory = '/'
|
||||||
|
. $this->getConfig()->release('directory', 'releases')
|
||||||
|
. '/'
|
||||||
|
. $this->getConfig()->getReleaseId();
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$releasesDirectory = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$localCommand = 'ssh -p ' . $this->getConfig()->getHostPort() . ' '
|
||||||
|
. '-q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no '
|
||||||
|
. $this->getConfig()->deployment('user') . '@' . $this->getConfig()->getHostName() . ' '
|
||||||
|
. '"cd ' . rtrim($this->getConfig()->deployment('to'), '/') . $releasesDirectory . ' && '
|
||||||
|
. str_replace('"', '\"', $command) . '"';
|
||||||
|
|
||||||
|
return $this->runCommandLocal($localCommand, $output);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs a Shell Command Localy or in the Remote Host based on the Task Stage.
|
||||||
|
* If the stage is "deploy" then it will be executed in the remote host.
|
||||||
|
* @param string $command
|
||||||
|
* @param string $output
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
protected final function runCommand($command, &$output = null)
|
||||||
|
{
|
||||||
|
if ($this->getStage() == self::STAGE_DEPLOY) {
|
||||||
|
return $this->runCommandRemote($command, $output);
|
||||||
|
} else {
|
||||||
|
return $this->runCommandLocal($command, $output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
75
Mage/Task/BuiltIn/Deployment/ReleaseTask.php
Normal file
75
Mage/Task/BuiltIn/Deployment/ReleaseTask.php
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Task\BuiltIn\Deployment;
|
||||||
|
|
||||||
|
use Mage\Task\AbstractTask;
|
||||||
|
use Mage\Task\Releases\IsReleaseAware;
|
||||||
|
use Mage\Task\Releases\SkipOnOverride;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task for Releasing a Deploy
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
class ReleaseTask extends AbstractTask implements IsReleaseAware, SkipOnOverride
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* (non-PHPdoc)
|
||||||
|
* @see \Mage\Task\AbstractTask::getName()
|
||||||
|
*/
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'Releasing [built-in]';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Releases a Deployment: points the current symbolic link to the release directory
|
||||||
|
* @see \Mage\Task\AbstractTask::run()
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
if ($this->getConfig()->release('enabled', false) == true) {
|
||||||
|
$releasesDirectory = $this->getConfig()->release('directory', 'releases');
|
||||||
|
$symlink = $this->getConfig()->release('symlink', 'current');
|
||||||
|
|
||||||
|
if (substr($symlink, 0, 1) == '/') {
|
||||||
|
$releasesDirectory = rtrim($this->getConfig()->deployment('to'), '/') . '/' . $releasesDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
$currentCopy = $releasesDirectory . '/' . $this->getConfig()->getReleaseId();
|
||||||
|
|
||||||
|
// Fetch the user and group from base directory; defaults usergroup to 33:33
|
||||||
|
$userGroup = '33:33';
|
||||||
|
$resultFetch = $this->runCommandRemote('ls -ld . | awk \'{print \$3":"\$4}\'', $userGroup);
|
||||||
|
|
||||||
|
// Remove symlink if exists; create new symlink and change owners
|
||||||
|
$command = 'rm -f ' . $symlink
|
||||||
|
. ' ; '
|
||||||
|
. 'ln -sf ' . $currentCopy . ' ' . $symlink
|
||||||
|
. ' && '
|
||||||
|
. 'chown -h ' . $userGroup . ' ' . $symlink
|
||||||
|
. ' && '
|
||||||
|
. 'chown -R ' . $userGroup . ' ' . $currentCopy;
|
||||||
|
$result = $this->runCommandRemote($command);
|
||||||
|
|
||||||
|
// Set Directory Releases to same owner
|
||||||
|
$result = $this->runCommandRemote('chown ' . $userGroup . ' ' . $releasesDirectory);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
44
Mage/Task/BuiltIn/Deployment/Strategy/DisabledTask.php
Normal file
44
Mage/Task/BuiltIn/Deployment/Strategy/DisabledTask.php
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Task\BuiltIn\Deployment\Strategy;
|
||||||
|
|
||||||
|
use Mage\Task\AbstractTask;
|
||||||
|
use Mage\Task\Releases\IsReleaseAware;
|
||||||
|
use Mage\Task\SkipException;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deployment Strategy is Disabled
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
class DisabledTask extends AbstractTask implements IsReleaseAware
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* (non-PHPdoc)
|
||||||
|
* @see \Mage\Task\AbstractTask::getName()
|
||||||
|
*/
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'Disabled Deployment [built-in]';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deployment Strategy is Disabled
|
||||||
|
* @see \Mage\Task\AbstractTask::run()
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
throw new SkipException;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
79
Mage/Task/BuiltIn/Deployment/Strategy/GitRebaseTask.php
Normal file
79
Mage/Task/BuiltIn/Deployment/Strategy/GitRebaseTask.php
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Task\BuiltIn\Deployment\Strategy;
|
||||||
|
|
||||||
|
use Mage\Task\AbstractTask;
|
||||||
|
use Mage\Task\Releases\IsReleaseAware;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task for using Git Working Copy as the Deployed Code
|
||||||
|
*
|
||||||
|
* @author Oscar Reales <oreales@gmail.com>
|
||||||
|
*/
|
||||||
|
class GitRebaseTask extends AbstractTask implements IsReleaseAware
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* (non-PHPdoc)
|
||||||
|
* @see \Mage\Task\AbstractTask::getName()
|
||||||
|
*/
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'Deploy via Git Rebase [built-in]';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rebases the Git Working Copy as the Deployed Code
|
||||||
|
* @see \Mage\Task\AbstractTask::run()
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
$branch = $this->getParameter('branch');
|
||||||
|
$remote = $this->getParameter('remote');
|
||||||
|
|
||||||
|
// Fetch Remote
|
||||||
|
$command = 'git fetch ' . $remote;
|
||||||
|
$result = $this->runCommandRemote($command) && $result;
|
||||||
|
|
||||||
|
// Checkout
|
||||||
|
$command = 'git checkout ' . $branch;
|
||||||
|
$result = $this->runCommandRemote($command) && $result;
|
||||||
|
|
||||||
|
// Check Working Copy status
|
||||||
|
$stashed = false;
|
||||||
|
$status = '';
|
||||||
|
$command = 'git checkout ' . $branch;
|
||||||
|
$result = $this->runCommandRemote($command) && $result;
|
||||||
|
|
||||||
|
// Stash if Working Copy is not clean
|
||||||
|
if(!$status) {
|
||||||
|
$stashResult = '';
|
||||||
|
$command = 'git stash';
|
||||||
|
$result = $this->runCommandRemote($command, $stashResult) && $result;
|
||||||
|
if($stashResult != "No local changes to save") {
|
||||||
|
$stashed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rebase
|
||||||
|
$command = 'git rebase ' . $remote . '/' . $branch;
|
||||||
|
$result = $this->runCommandRemote($command) && $result;
|
||||||
|
|
||||||
|
// If Stashed, restore.
|
||||||
|
if ($stashed) {
|
||||||
|
$command = 'git stash pop';
|
||||||
|
$result = $this->runCommandRemote($command) && $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
142
Mage/Task/BuiltIn/Deployment/Strategy/RsyncTask.php
Normal file
142
Mage/Task/BuiltIn/Deployment/Strategy/RsyncTask.php
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Task\BuiltIn\Deployment\Strategy;
|
||||||
|
|
||||||
|
use Mage\Task\AbstractTask;
|
||||||
|
use Mage\Task\Releases\IsReleaseAware;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task for Sync the Local Code to the Remote Hosts via RSYNC
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
class RsyncTask extends AbstractTask implements IsReleaseAware
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* (non-PHPdoc)
|
||||||
|
* @see \Mage\Task\AbstractTask::getName()
|
||||||
|
*/
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
if ($this->getConfig()->release('enabled', false) == true) {
|
||||||
|
if ($this->getConfig()->getParameter('overrideRelease', false) == true) {
|
||||||
|
return 'Deploy via Rsync (with Releases override) [built-in]';
|
||||||
|
} else {
|
||||||
|
return 'Deploy via Rsync (with Releases) [built-in]';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return 'Deploy via Rsync [built-in]';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Syncs the Local Code to the Remote Host
|
||||||
|
* @see \Mage\Task\AbstractTask::run()
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
$overrideRelease = $this->getParameter('overrideRelease', false);
|
||||||
|
|
||||||
|
if ($overrideRelease == true) {
|
||||||
|
$releaseToOverride = false;
|
||||||
|
$resultFetch = $this->runCommandRemote('ls -ld current | cut -d"/" -f2', $releaseToOverride);
|
||||||
|
if (is_numeric($releaseToOverride)) {
|
||||||
|
$this->getConfig()->setReleaseId($releaseToOverride);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$excludes = array(
|
||||||
|
'.git',
|
||||||
|
'.svn',
|
||||||
|
'.mage',
|
||||||
|
'.gitignore',
|
||||||
|
'.gitkeep',
|
||||||
|
'nohup.out'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Look for User Excludes
|
||||||
|
$userExcludes = $this->getConfig()->deployment('excludes', array());
|
||||||
|
|
||||||
|
// If we are working with releases
|
||||||
|
$deployToDirectory = $this->getConfig()->deployment('to');
|
||||||
|
if ($this->getConfig()->release('enabled', false) == true) {
|
||||||
|
$releasesDirectory = $this->getConfig()->release('directory', 'releases');
|
||||||
|
|
||||||
|
$deployToDirectory = rtrim($this->getConfig()->deployment('to'), '/')
|
||||||
|
. '/' . $releasesDirectory
|
||||||
|
. '/' . $this->getConfig()->getReleaseId();
|
||||||
|
$this->runCommandRemote('mkdir -p ' . $releasesDirectory . '/' . $this->getConfig()->getReleaseId());
|
||||||
|
}
|
||||||
|
|
||||||
|
$command = 'rsync -avz '
|
||||||
|
. '--rsh="ssh -p' . $this->getConfig()->getHostPort() . '" '
|
||||||
|
. $this->excludes(array_merge($excludes, $userExcludes)) . ' '
|
||||||
|
. $this->getConfig()->deployment('from') . ' '
|
||||||
|
. $this->getConfig()->deployment('user') . '@' . $this->getConfig()->getHostName() . ':' . $deployToDirectory;
|
||||||
|
|
||||||
|
$result = $this->runCommandLocal($command);
|
||||||
|
|
||||||
|
// Count Releases
|
||||||
|
if ($this->getConfig()->release('enabled', false) == true) {
|
||||||
|
$releasesDirectory = $this->getConfig()->release('directory', 'releases');
|
||||||
|
$symlink = $this->getConfig()->release('symlink', 'current');
|
||||||
|
|
||||||
|
if (substr($symlink, 0, 1) == '/') {
|
||||||
|
$releasesDirectory = rtrim($this->getConfig()->deployment('to'), '/') . '/' . $releasesDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
$maxReleases = $this->getConfig()->release('max', false);
|
||||||
|
if (($maxReleases !== false) && ($maxReleases > 0)) {
|
||||||
|
$releasesList = '';
|
||||||
|
$countReleasesFetch = $this->runCommandRemote('ls -1 ' . $releasesDirectory, $releasesList);
|
||||||
|
$releasesList = trim($releasesList);
|
||||||
|
|
||||||
|
if ($releasesList != '') {
|
||||||
|
$releasesList = explode(PHP_EOL, $releasesList);
|
||||||
|
if (count($releasesList) > $maxReleases) {
|
||||||
|
$releasesToDelete = array_diff($releasesList, array($this->getConfig()->getReleaseId()));
|
||||||
|
sort($releasesToDelete);
|
||||||
|
$releasesToDeleteCount = count($releasesToDelete) - $maxReleases;
|
||||||
|
$releasesToDelete = array_slice($releasesToDelete, 0, $releasesToDeleteCount + 1);
|
||||||
|
|
||||||
|
foreach ($releasesToDelete as $releaseIdToDelete) {
|
||||||
|
$directoryToDelete = $releasesDirectory . '/' . $releaseIdToDelete;
|
||||||
|
if ($directoryToDelete != '/') {
|
||||||
|
$command = 'rm -rf ' . $directoryToDelete;
|
||||||
|
$result = $result && $this->runCommandRemote($command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates the Excludes for rsync
|
||||||
|
* @param array $excludes
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function excludes(Array $excludes)
|
||||||
|
{
|
||||||
|
$excludesRsync = '';
|
||||||
|
foreach ($excludes as $exclude) {
|
||||||
|
$excludesRsync .= ' --exclude ' . $exclude . ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
$excludesRsync = trim($excludesRsync);
|
||||||
|
return $excludesRsync;
|
||||||
|
}
|
||||||
|
}
|
161
Mage/Task/BuiltIn/Deployment/Strategy/TarGzTask.php
Normal file
161
Mage/Task/BuiltIn/Deployment/Strategy/TarGzTask.php
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Task\BuiltIn\Deployment\Strategy;
|
||||||
|
|
||||||
|
use Mage\Task\AbstractTask;
|
||||||
|
use Mage\Task\Releases\IsReleaseAware;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task for Sync the Local Code to the Remote Hosts via Tar GZ
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
class TarGzTask extends AbstractTask implements IsReleaseAware
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* (non-PHPdoc)
|
||||||
|
* @see \Mage\Task\AbstractTask::getName()
|
||||||
|
*/
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
if ($this->getConfig()->release('enabled', false) == true) {
|
||||||
|
if ($this->getConfig()->getParameter('overrideRelease', false) == true) {
|
||||||
|
return 'Deploy via TarGz (with Releases override) [built-in]';
|
||||||
|
} else {
|
||||||
|
return 'Deploy via TarGz (with Releases) [built-in]';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return 'Deploy via TarGz [built-in]';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Syncs the Local Code to the Remote Host
|
||||||
|
* @see \Mage\Task\AbstractTask::run()
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
$overrideRelease = $this->getParameter('overrideRelease', false);
|
||||||
|
|
||||||
|
if ($overrideRelease == true) {
|
||||||
|
$releaseToOverride = false;
|
||||||
|
$resultFetch = $this->runCommandRemote('ls -ld current | cut -d"/" -f2', $releaseToOverride);
|
||||||
|
if (is_numeric($releaseToOverride)) {
|
||||||
|
$this->getConfig()->setReleaseId($releaseToOverride);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$excludes = array(
|
||||||
|
'.git',
|
||||||
|
'.svn',
|
||||||
|
'.mage',
|
||||||
|
'.gitignore',
|
||||||
|
'.gitkeep',
|
||||||
|
'nohup.out'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Look for User Excludes
|
||||||
|
$userExcludes = $this->getConfig()->deployment('excludes', array());
|
||||||
|
|
||||||
|
// If we are working with releases
|
||||||
|
$deployToDirectory = $this->getConfig()->deployment('to');
|
||||||
|
if ($this->getConfig()->release('enabled', false) == true) {
|
||||||
|
$releasesDirectory = $this->getConfig()->release('directory', 'releases');
|
||||||
|
|
||||||
|
$deployToDirectory = rtrim($this->getConfig()->deployment('to'), '/')
|
||||||
|
. '/' . $releasesDirectory
|
||||||
|
. '/' . $this->getConfig()->getReleaseId();
|
||||||
|
$this->runCommandRemote('mkdir -p ' . $releasesDirectory . '/' . $this->getConfig()->getReleaseId());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create Tar Gz
|
||||||
|
$localTarGz = tempnam(sys_get_temp_dir(), 'mage');
|
||||||
|
$remoteTarGz = basename($localTarGz);
|
||||||
|
$excludes = array_merge($excludes, $userExcludes);
|
||||||
|
$excludeCmd = '';
|
||||||
|
foreach ($excludes as $excludeFile) {
|
||||||
|
$excludeCmd .= ' --exclude=' . $excludeFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
$command = 'tar cfz ' . $localTarGz . '.tar.gz ' . $excludeCmd . ' ' . $this->getConfig()->deployment('from');
|
||||||
|
$result = $this->runCommandLocal($command);
|
||||||
|
|
||||||
|
// Copy Tar Gz to Remote Host
|
||||||
|
$command = 'scp -P ' . $this->getConfig()->getHostPort() . ' ' . $localTarGz . '.tar.gz '
|
||||||
|
. $this->getConfig()->deployment('user') . '@' . $this->getConfig()->getHostName() . ':' . $deployToDirectory;
|
||||||
|
$result = $this->runCommandLocal($command) && $result;
|
||||||
|
|
||||||
|
// Extract Tar Gz
|
||||||
|
if ($this->getConfig()->release('enabled', false) == true) {
|
||||||
|
$releasesDirectory = $this->getConfig()->release('directory', 'releases');
|
||||||
|
|
||||||
|
$deployToDirectory = $releasesDirectory . '/' . $this->getConfig()->getReleaseId();
|
||||||
|
$command = 'cd ' . $deployToDirectory . ' && tar xfz ' . $remoteTarGz . '.tar.gz';
|
||||||
|
} else {
|
||||||
|
$command = 'tar xfz ' . $remoteTarGz . '.tar.gz';
|
||||||
|
}
|
||||||
|
$result = $this->runCommandRemote($command) && $result;
|
||||||
|
|
||||||
|
// Delete Tar Gz from Remote Host
|
||||||
|
if ($this->getConfig()->release('enabled', false) == true) {
|
||||||
|
$releasesDirectory = $this->getConfig()->release('directory', 'releases');
|
||||||
|
|
||||||
|
$deployToDirectory = $releasesDirectory . '/' . $this->getConfig()->getReleaseId();
|
||||||
|
$command = 'rm ' . $deployToDirectory . '/' . $remoteTarGz . '.tar.gz';
|
||||||
|
} else {
|
||||||
|
$command = 'rm ' . $remoteTarGz . '.tar.gz';
|
||||||
|
}
|
||||||
|
$result = $this->runCommandRemote($command) && $result;
|
||||||
|
|
||||||
|
// Delete Tar Gz from Local
|
||||||
|
$command = 'rm ' . $localTarGz . ' ' . $localTarGz . '.tar.gz';
|
||||||
|
$result = $this->runCommandLocal($command) && $result;
|
||||||
|
|
||||||
|
// Count Releases
|
||||||
|
if ($this->getConfig()->release('enabled', false) == true) {
|
||||||
|
$releasesDirectory = $this->getConfig()->release('directory', 'releases');
|
||||||
|
$symlink = $this->getConfig()->release('symlink', 'current');
|
||||||
|
|
||||||
|
if (substr($symlink, 0, 1) == '/') {
|
||||||
|
$releasesDirectory = rtrim($this->getConfig()->deployment('to'), '/') . '/' . $releasesDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
$maxReleases = $this->getConfig()->release('max', false);
|
||||||
|
if (($maxReleases !== false) && ($maxReleases > 0)) {
|
||||||
|
$releasesList = '';
|
||||||
|
$countReleasesFetch = $this->runCommandRemote('ls -1 ' . $releasesDirectory, $releasesList);
|
||||||
|
$releasesList = trim($releasesList);
|
||||||
|
|
||||||
|
if ($releasesList != '') {
|
||||||
|
$releasesList = explode(PHP_EOL, $releasesList);
|
||||||
|
if (count($releasesList) > $maxReleases) {
|
||||||
|
$releasesToDelete = array_diff($releasesList, array($this->getConfig()->getReleaseId()));
|
||||||
|
sort($releasesToDelete);
|
||||||
|
$releasesToDeleteCount = count($releasesToDelete) - $maxReleases;
|
||||||
|
$releasesToDelete = array_slice($releasesToDelete, 0, $releasesToDeleteCount + 1);
|
||||||
|
|
||||||
|
foreach ($releasesToDelete as $releaseIdToDelete) {
|
||||||
|
$directoryToDelete = $releasesDirectory . '/' . $releaseIdToDelete;
|
||||||
|
if ($directoryToDelete != '/') {
|
||||||
|
$command = 'rm -rf ' . $directoryToDelete;
|
||||||
|
$result = $result && $this->runCommandRemote($command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
44
Mage/Task/BuiltIn/Magento/ClearCacheTask.php
Normal file
44
Mage/Task/BuiltIn/Magento/ClearCacheTask.php
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Task\BuiltIn\Magento;
|
||||||
|
|
||||||
|
use Mage\Task\AbstractTask;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task for Clearing Cache
|
||||||
|
*
|
||||||
|
* @author Oscar Reales <oreales@gmail.com>
|
||||||
|
*/
|
||||||
|
class ClearCacheTask extends AbstractTask
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* (non-PHPdoc)
|
||||||
|
* @see \Mage\Task\AbstractTask::getName()
|
||||||
|
*/
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'Magento - Clean Cache [built-in]';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears Cache
|
||||||
|
* @see \Mage\Task\AbstractTask::run()
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
$command = 'rm -rf var/cache/*';
|
||||||
|
$result = $this->runCommand($command);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
44
Mage/Task/BuiltIn/Magento/ClearFullPageCacheTask.php
Normal file
44
Mage/Task/BuiltIn/Magento/ClearFullPageCacheTask.php
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Task\BuiltIn\Magento;
|
||||||
|
|
||||||
|
use Mage\Task\AbstractTask;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task for Clearing Full Page Cache
|
||||||
|
*
|
||||||
|
* @author Oscar Reales <oreales@gmail.com>
|
||||||
|
*/
|
||||||
|
class ClearFullPageCacheTask extends AbstractTask
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* (non-PHPdoc)
|
||||||
|
* @see \Mage\Task\AbstractTask::getName()
|
||||||
|
*/
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'Magento - Clean Full Page Cache [built-in]';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears Full Page Cache
|
||||||
|
* @see \Mage\Task\AbstractTask::run()
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
$command = 'rm -rf var/full_page_cache/*';
|
||||||
|
$result = $this->runCommand($command);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
152
Mage/Task/BuiltIn/Releases/ListTask.php
Normal file
152
Mage/Task/BuiltIn/Releases/ListTask.php
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Task\BuiltIn\Releases;
|
||||||
|
|
||||||
|
use Mage\Console;
|
||||||
|
use Mage\Task\AbstractTask;
|
||||||
|
use Mage\Task\Releases\IsReleaseAware;
|
||||||
|
|
||||||
|
use DateTime;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task for Listing Available Releases on an Environment
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
class ListTask extends AbstractTask implements IsReleaseAware
|
||||||
|
{
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'Listing releases [built-in]';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List the Available Releases on an Environment
|
||||||
|
* @see \Mage\Task\AbstractTask::run()
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
if ($this->getConfig()->release('enabled', false) == true) {
|
||||||
|
$releasesDirectory = $this->getConfig()->release('directory', 'releases');
|
||||||
|
$symlink = $this->getConfig()->release('symlink', 'current');
|
||||||
|
|
||||||
|
Console::output('Releases available on <dark_gray>' . $this->getConfig()->getHost() . '</dark_gray>');
|
||||||
|
|
||||||
|
// Get Releases
|
||||||
|
$output = '';
|
||||||
|
$result = $this->runCommandRemote('ls -1 ' . $releasesDirectory, $output);
|
||||||
|
$releases = ($output == '') ? array() : explode(PHP_EOL, $output);
|
||||||
|
|
||||||
|
// Get Current
|
||||||
|
$result = $this->runCommandRemote('ls -l ' . $symlink, $output);
|
||||||
|
$currentRelease = explode('/', $output);
|
||||||
|
$currentRelease = trim(array_pop($currentRelease));
|
||||||
|
|
||||||
|
if (count($releases) == 0) {
|
||||||
|
Console::output('<dark_gray>No releases available</dark_gray> ... ', 2);
|
||||||
|
} else {
|
||||||
|
rsort($releases);
|
||||||
|
$releases = array_slice($releases, 0, 10);
|
||||||
|
|
||||||
|
foreach ($releases as $releaseIndex => $release) {
|
||||||
|
$release = trim($release);
|
||||||
|
$releaseIndex = str_pad($releaseIndex * -1, 2, ' ', STR_PAD_LEFT);
|
||||||
|
$releaseDate = $release[0] . $release[1] . $release[2] .$release[3]
|
||||||
|
. '-'
|
||||||
|
. $release[4] . $release[5]
|
||||||
|
. '-'
|
||||||
|
. $release[6] . $release[7]
|
||||||
|
. ' '
|
||||||
|
. $release[8] . $release[9]
|
||||||
|
. ':'
|
||||||
|
. $release[10] . $release[11]
|
||||||
|
. ':'
|
||||||
|
. $release[12] . $release[13];
|
||||||
|
|
||||||
|
$isCurrent = '';
|
||||||
|
if ($currentRelease == $release) {
|
||||||
|
$isCurrent = ' <- current';
|
||||||
|
}
|
||||||
|
|
||||||
|
$dateDiff = $this->dateDiff($releaseDate);
|
||||||
|
|
||||||
|
Console::output(
|
||||||
|
'Release: <purple>' . $release . '</purple> '
|
||||||
|
. '- Date: <dark_gray>' . $releaseDate . '</dark_gray> '
|
||||||
|
. '- Index: <dark_gray>' . $releaseIndex . '</dark_gray>' . $dateDiff . $isCurrent, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Console::output('');
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Console::output('');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates a Human Readable Time Difference
|
||||||
|
* @param string $releaseDate
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function dateDiff($releaseDate)
|
||||||
|
{
|
||||||
|
$textDiff = '';
|
||||||
|
$releaseDate = new DateTime($releaseDate);
|
||||||
|
$now = new DateTime();
|
||||||
|
$diff = $now->diff($releaseDate);
|
||||||
|
|
||||||
|
if ($diff->format('%a') <= 7) {
|
||||||
|
if ($diff->format('%d') == 7) {
|
||||||
|
$textDiff = ' [a week ago] ';
|
||||||
|
|
||||||
|
} else if ($diff->format('%d') > 0 && $diff->format('%d') < 7) {
|
||||||
|
$days = $diff->format('%d');
|
||||||
|
if ($days <= 1) {
|
||||||
|
$textDiff = ' [one day ago] ';
|
||||||
|
} else {
|
||||||
|
$textDiff = ' [' . $days . ' days ago] ';
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if ($diff->format('%d') == 0 && $diff->format('%h') > 0) {
|
||||||
|
$hours = $diff->format('%h');
|
||||||
|
if ($hours <= 1) {
|
||||||
|
$textDiff = ' [one hour ago] ';
|
||||||
|
} else {
|
||||||
|
$textDiff = ' [' . $hours . ' hours ago] ';
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if ($diff->format('%d') == 0 && $diff->format('%h') == 0) {
|
||||||
|
$minutes = $diff->format('%i');
|
||||||
|
if ($minutes <= 1) {
|
||||||
|
$textDiff = ' [one minute ago] ';
|
||||||
|
} else {
|
||||||
|
$textDiff = ' [' . $minutes . ' minutes ago] ';
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if ($diff->format('%d') == 0 && $diff->format('%h') == 0 && $diff->format('%i') == 0) {
|
||||||
|
$seconds = $diff->format('%s');
|
||||||
|
if ($seconds < 10) {
|
||||||
|
$textDiff = ' [just now!] ';
|
||||||
|
} else {
|
||||||
|
$textDiff = ' [' . $seconds . ' seconds ago] ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $textDiff;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
170
Mage/Task/BuiltIn/Releases/RollbackTask.php
Normal file
170
Mage/Task/BuiltIn/Releases/RollbackTask.php
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Task\BuiltIn\Releases;
|
||||||
|
|
||||||
|
use Mage\Console;
|
||||||
|
use Mage\Task\Factory;
|
||||||
|
use Mage\Task\AbstractTask;
|
||||||
|
use Mage\Task\Releases\IsReleaseAware;
|
||||||
|
use Mage\Task\Releases\RollbackAware;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task for Performing a Rollback Operation
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
class RollbackTask extends AbstractTask implements IsReleaseAware
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The Relase ID to Rollback To
|
||||||
|
* @var integer
|
||||||
|
*/
|
||||||
|
protected $release = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPdoc)
|
||||||
|
* @see \Mage\Task\AbstractTask::getName()
|
||||||
|
*/
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'Rollback release [built-in]';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the Release ID to Rollback To
|
||||||
|
* @param integer $releaseId
|
||||||
|
* @return \Mage\Task\BuiltIn\Releases\RollbackTask
|
||||||
|
*/
|
||||||
|
public function setRelease($releaseId)
|
||||||
|
{
|
||||||
|
$this->release = $releaseId;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the Release ID to Rollback To
|
||||||
|
* @return integer
|
||||||
|
*/
|
||||||
|
public function getRelease()
|
||||||
|
{
|
||||||
|
return $this->release;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a Rollback Operation
|
||||||
|
* @see \Mage\Task\AbstractTask::run()
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
if ($this->getConfig()->release('enabled', false) == true) {
|
||||||
|
$releasesDirectory = $this->getConfig()->release('directory', 'releases');
|
||||||
|
$symlink = $this->getConfig()->release('symlink', 'current');
|
||||||
|
|
||||||
|
$output = '';
|
||||||
|
$result = $this->runCommandRemote('ls -1 ' . $releasesDirectory, $output);
|
||||||
|
$releases = ($output == '') ? array() : explode(PHP_EOL, $output);
|
||||||
|
|
||||||
|
if (count($releases) == 0) {
|
||||||
|
Console::output('Release are not available for <dark_gray>' . $this->getConfig()->getHost() . '</dark_gray> ... <red>FAIL</red>');
|
||||||
|
|
||||||
|
} else {
|
||||||
|
rsort($releases);
|
||||||
|
|
||||||
|
$releaseIsAvailable = false;
|
||||||
|
if ($this->getRelease() == '') {
|
||||||
|
$releaseId = $releases[0];
|
||||||
|
$releaseIsAvailable = true;
|
||||||
|
|
||||||
|
} else if ($this->getRelease() <= 0) {
|
||||||
|
$index = $this->getRelease() * -1;
|
||||||
|
if (isset($releases[$index])) {
|
||||||
|
$releaseId = $releases[$index];
|
||||||
|
$releaseIsAvailable = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (in_array($this->getRelease(), $releases)) {
|
||||||
|
$releaseId = $this->getRelease();
|
||||||
|
$releaseIsAvailable = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$releaseIsAvailable) {
|
||||||
|
Console::output('Release <dark_gray>' . $this->getRelease() . '</dark_gray> is invalid or unavailable for <dark_gray>' . $this->getConfig()->getHost() . '</dark_gray> ... <red>FAIL</red>');
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Console::output('Rollback release on <dark_gray>' . $this->getConfig()->getHost() . '</dark_gray>');
|
||||||
|
$rollbackTo = $releasesDirectory . '/' . $releaseId;
|
||||||
|
|
||||||
|
// Tasks
|
||||||
|
$tasks = 1;
|
||||||
|
$completedTasks = 0;
|
||||||
|
$tasksToRun = $this->getConfig()->getTasks();
|
||||||
|
$this->getConfig()->setReleaseId($releaseId);
|
||||||
|
|
||||||
|
foreach ($tasksToRun as $taskData) {
|
||||||
|
$task = Factory::get($taskData, $this->getConfig(), true, self::STAGE_DEPLOY);
|
||||||
|
$task->init();
|
||||||
|
Console::output('Running <purple>' . $task->getName() . '</purple> ... ', 2, false);
|
||||||
|
|
||||||
|
if ($task instanceOf RollbackAware) {
|
||||||
|
$tasks++;
|
||||||
|
$result = $task->run();
|
||||||
|
|
||||||
|
if ($result == true) {
|
||||||
|
Console::output('<green>OK</green>', 0);
|
||||||
|
$completedTasks++;
|
||||||
|
} else {
|
||||||
|
Console::output('<red>FAIL</red>', 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Console::output('<yellow>SKIPPED</yellow>', 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Changing Release
|
||||||
|
Console::output('Running <purple>Rollback Release [id=' . $releaseId . ']</purple> ... ', 2, false);
|
||||||
|
|
||||||
|
$userGroup = '';
|
||||||
|
$resultFetch = $this->runCommandRemote('ls -ld ' . $rollbackTo . ' | awk \'{print \$3":"\$4}\'', $userGroup);
|
||||||
|
$command = 'rm -f ' . $symlink
|
||||||
|
. ' && '
|
||||||
|
. 'ln -sf ' . $rollbackTo . ' ' . $symlink
|
||||||
|
. ' && '
|
||||||
|
. 'chown -h ' . $userGroup . ' ' . $symlink;
|
||||||
|
$result = $this->runCommandRemote($command);
|
||||||
|
|
||||||
|
if ($result) {
|
||||||
|
Console::output('<green>OK</green>', 0);
|
||||||
|
$completedTasks++;
|
||||||
|
} else {
|
||||||
|
Console::output('<red>FAIL</red>', 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($completedTasks == $tasks) {
|
||||||
|
$tasksColor = 'green';
|
||||||
|
} else {
|
||||||
|
$tasksColor = 'red';
|
||||||
|
}
|
||||||
|
|
||||||
|
Console::output('Release rollback on <dark_gray>' . $this->getConfig()->getHost() . '</dark_gray> compted: <' . $tasksColor . '>' . $completedTasks . '/' . $tasks . '</' . $tasksColor . '> tasks done.', 1, 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
111
Mage/Task/BuiltIn/Scm/ChangeBranchTask.php
Normal file
111
Mage/Task/BuiltIn/Scm/ChangeBranchTask.php
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Task\BuiltIn\Scm;
|
||||||
|
|
||||||
|
use Mage\Task\AbstractTask;
|
||||||
|
use Mage\Task\SkipException;
|
||||||
|
use Mage\Task\ErrorWithMessageException;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task for Changing the Branch of the SCM
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
class ChangeBranchTask extends AbstractTask
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Branch the executiong began with
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected static $startingBranch = 'master';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the Task
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $name = 'SCM Changing branch [built-in]';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPdoc)
|
||||||
|
* @see \Mage\Task\AbstractTask::getName()
|
||||||
|
*/
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPdoc)
|
||||||
|
* @see \Mage\Task\AbstractTask::init()
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$scmType = $this->getConfig()->general('scm');
|
||||||
|
|
||||||
|
switch ($scmType) {
|
||||||
|
case 'git':
|
||||||
|
$this->name = 'SCM Changing branch (GIT) [built-in]';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the Branch of the SCM
|
||||||
|
* @see \Mage\Task\AbstractTask::run()
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
$scmConfig = $this->getConfig()->general('scm', array());
|
||||||
|
switch ((isset($scmConfig['type']) ? $scmConfig['type'] : false)) {
|
||||||
|
case 'git':
|
||||||
|
if ($this->getParameter('_changeBranchRevert', false)) {
|
||||||
|
$command = 'git checkout ' . self::$startingBranch;
|
||||||
|
$result = $this->runCommandLocal($command);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$command = 'git branch | grep \'*\' | cut -d\' \' -f 2';
|
||||||
|
$currentBranch = 'master';
|
||||||
|
$result = $this->runCommandLocal($command, $currentBranch);
|
||||||
|
|
||||||
|
$scmData = $this->getConfig()->deployment('scm', false);
|
||||||
|
|
||||||
|
if ($result && is_array($scmData) && isset($scmData['branch']) && $scmData['branch'] != $currentBranch) {
|
||||||
|
$command = 'git branch | grep \'' . $scmData['branch'] . '\' | tr -s \' \' | sed \'s/^[ ]//g\'';
|
||||||
|
$isBranchTracked = '';
|
||||||
|
$result = $this->runCommandLocal($command, $isBranchTracked);
|
||||||
|
|
||||||
|
if ($isBranchTracked == '') {
|
||||||
|
throw new ErrorWithMessageException('The branch <purple>' . $scmData['branch'] . '</purple> must be tracked.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$branch = $this->getParameter('branch', $scmData['branch']);
|
||||||
|
$command = 'git checkout ' . $branch;
|
||||||
|
$result = $this->runCommandLocal($command);
|
||||||
|
|
||||||
|
self::$startingBranch = $currentBranch;
|
||||||
|
} else {
|
||||||
|
throw new SkipException;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new SkipException;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->getConfig()->reload();
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
89
Mage/Task/BuiltIn/Scm/CloneTask.php
Normal file
89
Mage/Task/BuiltIn/Scm/CloneTask.php
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Task\BuiltIn\Scm;
|
||||||
|
|
||||||
|
use Mage\Task\AbstractTask;
|
||||||
|
use Mage\Task\SkipException;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task for Clonning a Repository
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
class CloneTask extends AbstractTask
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Name of the Task
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $name = 'SCM Clone [built-in]';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Source of the Repo
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $source = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPdoc)
|
||||||
|
* @see \Mage\Task\AbstractTask::getName()
|
||||||
|
*/
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPdoc)
|
||||||
|
* @see \Mage\Task\AbstractTask::init()
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->source = $this->getConfig()->deployment('source');
|
||||||
|
switch ($this->source['type']) {
|
||||||
|
case 'git':
|
||||||
|
$this->name = 'SCM Clone (GIT) [built-in]';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clones a Repository
|
||||||
|
* @see \Mage\Task\AbstractTask::run()
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
$this->runCommandLocal('mkdir -p ' . $this->source['temporal']);
|
||||||
|
switch ($this->source['type']) {
|
||||||
|
case 'git':
|
||||||
|
// Clone Repo
|
||||||
|
$command = 'cd ' . $this->source['temporal'] . ' ; '
|
||||||
|
. 'git clone ' . $this->source['repository'] . ' . ';
|
||||||
|
$result = $this->runCommandLocal($command);
|
||||||
|
|
||||||
|
// Checkout Branch
|
||||||
|
$command = 'cd ' . $this->source['temporal'] . ' ; '
|
||||||
|
. 'git checkout ' . $this->source['from'];
|
||||||
|
$result = $result && $this->runCommandLocal($command);
|
||||||
|
|
||||||
|
$this->getConfig()->setFrom($this->source['temporal']);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new SkipException;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
64
Mage/Task/BuiltIn/Scm/RemoveCloneTask.php
Normal file
64
Mage/Task/BuiltIn/Scm/RemoveCloneTask.php
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Task\BuiltIn\Scm;
|
||||||
|
|
||||||
|
use Mage\Task\AbstractTask;
|
||||||
|
use Mage\Task\SkipException;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task for Removing an used Cloned Repository
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
class RemoveCloneTask extends AbstractTask
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Name of the Task
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $name = 'SCM Remove Clone [built-in]';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Source of the Repo
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $source = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPdoc)
|
||||||
|
* @see \Mage\Task\AbstractTask::getName()
|
||||||
|
*/
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPdoc)
|
||||||
|
* @see \Mage\Task\AbstractTask::init()
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->source = $this->getConfig()->deployment('source');
|
||||||
|
switch ($this->source['type']) {
|
||||||
|
case 'git':
|
||||||
|
$this->name = 'SCM Remove Clone (GIT) [built-in]';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
return $this->runCommandLocal('rm -rf ' . $this->source['temporal']);
|
||||||
|
}
|
||||||
|
}
|
74
Mage/Task/BuiltIn/Scm/UpdateTask.php
Normal file
74
Mage/Task/BuiltIn/Scm/UpdateTask.php
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Task\BuiltIn\Scm;
|
||||||
|
|
||||||
|
use Mage\Task\AbstractTask;
|
||||||
|
use Mage\Task\SkipException;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task for Updating a Working Copy
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
class UpdateTask extends AbstractTask
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Name of the Task
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $name = 'SCM Update [built-in]';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPdoc)
|
||||||
|
* @see \Mage\Task\AbstractTask::getName()
|
||||||
|
*/
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return $this->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPdoc)
|
||||||
|
* @see \Mage\Task\AbstractTask::init()
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
switch ($this->getConfig()->general('scm')) {
|
||||||
|
case 'git':
|
||||||
|
$this->name = 'SCM Update (GIT) [built-in]';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the Working Copy
|
||||||
|
* @see \Mage\Task\AbstractTask::run()
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
switch ($this->getConfig()->general('scm')) {
|
||||||
|
case 'git':
|
||||||
|
$command = 'git pull';
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new SkipException;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $this->runCommandLocal($command);
|
||||||
|
$this->getConfig()->reload();
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
47
Mage/Task/BuiltIn/Symfony2/AsseticDumpTask.php
Normal file
47
Mage/Task/BuiltIn/Symfony2/AsseticDumpTask.php
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Task\BuiltIn\Symfony2;
|
||||||
|
|
||||||
|
use Mage\Task\AbstractTask;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task for Dumping Assetics
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
class AsseticDumpTask extends AbstractTask
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* (non-PHPdoc)
|
||||||
|
* @see \Mage\Task\AbstractTask::getName()
|
||||||
|
*/
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'Symfony v2 - Assetic Dump [built-in]';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dumps Assetics
|
||||||
|
* @see \Mage\Task\AbstractTask::run()
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
// Options
|
||||||
|
$env = $this->getParameter('env', 'dev');
|
||||||
|
|
||||||
|
$command = 'app/console assetic:dump --env=' . $env;
|
||||||
|
$result = $this->runCommand($command);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
54
Mage/Task/BuiltIn/Symfony2/AssetsInstallTask.php
Normal file
54
Mage/Task/BuiltIn/Symfony2/AssetsInstallTask.php
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Task\BuiltIn\Symfony2;
|
||||||
|
|
||||||
|
use Mage\Task\AbstractTask;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task for Installing Assets
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
class AssetsInstallTask extends AbstractTask
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* (non-PHPdoc)
|
||||||
|
* @see \Mage\Task\AbstractTask::getName()
|
||||||
|
*/
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'Symfony v2 - Assets Install [built-in]';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Installs Assets
|
||||||
|
* @see \Mage\Task\AbstractTask::run()
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
// Options
|
||||||
|
$target = $this->getParameter('target', 'web');
|
||||||
|
$symlink = $this->getParameter('symlink', false);
|
||||||
|
$relative = $this->getParameter('relative', false);
|
||||||
|
$env = $this->getParameter('env', 'dev');
|
||||||
|
|
||||||
|
if ($relative) {
|
||||||
|
$symlink = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$command = 'app/console assets:install ' . ($symlink ? '--symlink' : '') . ' ' . ($relative ? '--relative' : '') . ' --env=' . $env . ' ' . $target;
|
||||||
|
$result = $this->runCommand($command);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
47
Mage/Task/BuiltIn/Symfony2/CacheClearTask.php
Normal file
47
Mage/Task/BuiltIn/Symfony2/CacheClearTask.php
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Task\BuiltIn\Symfony2;
|
||||||
|
|
||||||
|
use Mage\Task\AbstractTask;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task for Clearing the Cache
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
class CacheClearTask extends AbstractTask
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* (non-PHPdoc)
|
||||||
|
* @see \Mage\Task\AbstractTask::getName()
|
||||||
|
*/
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'Symfony v2 - Cache Clear [built-in]';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the Cache
|
||||||
|
* @see \Mage\Task\AbstractTask::run()
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
// Options
|
||||||
|
$env = $this->getParameter('env', 'dev');
|
||||||
|
|
||||||
|
$command = 'app/console cache:clear --env=' . $env;
|
||||||
|
$result = $this->runCommand($command);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
47
Mage/Task/BuiltIn/Symfony2/CacheWarmupTask.php
Normal file
47
Mage/Task/BuiltIn/Symfony2/CacheWarmupTask.php
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Task\BuiltIn\Symfony2;
|
||||||
|
|
||||||
|
use Mage\Task\AbstractTask;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task for Warming Up the Cache
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
class CacheWarmupTask extends AbstractTask
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* (non-PHPdoc)
|
||||||
|
* @see \Mage\Task\AbstractTask::getName()
|
||||||
|
*/
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'Symfony v2 - Cache Warmup [built-in]';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Warms Up Cache
|
||||||
|
* @see \Mage\Task\AbstractTask::run()
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
// Options
|
||||||
|
$env = $this->getParameter('env', 'dev');
|
||||||
|
|
||||||
|
$command = 'app/console cache:warmup --env=' . $env;
|
||||||
|
$result = $this->runCommand($command);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
22
Mage/Task/ErrorWithMessageException.php
Normal file
22
Mage/Task/ErrorWithMessageException.php
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Task;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception that indicates that the Task has an Error and also a Message indicating the Error
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
class ErrorWithMessageException extends Exception
|
||||||
|
{
|
||||||
|
}
|
71
Mage/Task/Factory.php
Normal file
71
Mage/Task/Factory.php
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Task;
|
||||||
|
|
||||||
|
use Mage\Config;
|
||||||
|
use Mage\Autoload;
|
||||||
|
use Mage\Task\ErrorWithMessageException;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task Factory
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
class Factory
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Gets an instance of a Task.
|
||||||
|
*
|
||||||
|
* @param string|array $taskData
|
||||||
|
* @param Mage\Config $taskConfig
|
||||||
|
* @param boolean $inRollback
|
||||||
|
* @param string $stage
|
||||||
|
* @return \Mage\Task\AbstractTask
|
||||||
|
*/
|
||||||
|
public static function get($taskData, Config $taskConfig, $inRollback = false, $stage = null)
|
||||||
|
{
|
||||||
|
if (is_array($taskData)) {
|
||||||
|
$taskName = $taskData['name'];
|
||||||
|
$taskParameters = $taskData['parameters'];
|
||||||
|
} else {
|
||||||
|
$taskName = $taskData;
|
||||||
|
$taskParameters = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$instance = null;
|
||||||
|
$taskName = ucwords(str_replace('-', ' ', $taskName));
|
||||||
|
$taskName = str_replace(' ', '', $taskName);
|
||||||
|
|
||||||
|
if (strpos($taskName, '/') === false) {
|
||||||
|
Autoload::loadUserTask($taskName);
|
||||||
|
$className = 'Task\\' . ucfirst($taskName);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$taskName = str_replace(' ', '\\', ucwords(str_replace('/', ' ', $taskName)));
|
||||||
|
$className = 'Mage\\Task\\BuiltIn\\' . $taskName . 'Task';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (class_exists($className) || Autoload::isLoadable($className)) {
|
||||||
|
$instance = new $className($taskConfig, $inRollback, $stage, $taskParameters);
|
||||||
|
} else {
|
||||||
|
throw new ErrorWithMessageException('The Task "' . $taskName . '" doesn\'t exists.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!($instance instanceOf AbstractTask)) {
|
||||||
|
throw new Exception('The Task ' . $taskName . ' must be an instance of Mage\Task\AbstractTask.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $instance;
|
||||||
|
}
|
||||||
|
}
|
20
Mage/Task/Releases/IsReleaseAware.php
Normal file
20
Mage/Task/Releases/IsReleaseAware.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Task\Releases;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that the Task is Relase Aware/Dependant
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
interface IsReleaseAware
|
||||||
|
{
|
||||||
|
}
|
20
Mage/Task/Releases/RollbackAware.php
Normal file
20
Mage/Task/Releases/RollbackAware.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Task\Releases;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that the Task is Aware of Rollbacks
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
interface RollbackAware
|
||||||
|
{
|
||||||
|
}
|
20
Mage/Task/Releases/SkipOnOverride.php
Normal file
20
Mage/Task/Releases/SkipOnOverride.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Task\Releases;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that the Task will be Skipped on Relase Override
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
interface SkipOnOverride
|
||||||
|
{
|
||||||
|
}
|
22
Mage/Task/SkipException.php
Normal file
22
Mage/Task/SkipException.php
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Mage\Task;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception that indicates that the Task was Skipped
|
||||||
|
*
|
||||||
|
* @author Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*/
|
||||||
|
class SkipException extends Exception
|
||||||
|
{
|
||||||
|
}
|
1046
Mage/spyc.php
Normal file
1046
Mage/spyc.php
Normal file
File diff suppressed because it is too large
Load Diff
66
README.md
66
README.md
@ -1,29 +1,59 @@
|
|||||||
# Magallanes
|
# Magallanes #
|
||||||
[](https://insight.sensiolabs.com/projects/ed0de53a-a12e-459b-9464-34def5907b56)
|
|
||||||
[](https://travis-ci.org/andres-montanez/Magallanes)
|
|
||||||
[](https://coveralls.io/github/andres-montanez/Magallanes?branch=master)
|
|
||||||
[](https://scrutinizer-ci.com/g/andres-montanez/Magallanes/)
|
|
||||||
[](https://packagist.org/packages/andres-montanez/magallanes)
|
|
||||||
[](https://packagist.org/packages/andres-montanez/magallanes)
|
|
||||||
[](https://packagist.org/packages/andres-montanez/magallanes)
|
|
||||||
[](https://packagist.org/packages/andres-montanez/magallanes)
|
|
||||||
|
|
||||||
### What's Magallanes?
|
### What's Magallanes? ###
|
||||||
**Magallanes** is a deployment tool for made with PHP for PHP applications; it's quite simple to use and manage. For more information and documentation please visit https://magephp.com
|
Magallanes is a deployment tool for PHP applications; it's quite simple to use and manage.
|
||||||
|
It will get your application to a safe harbor.
|
||||||
|
|
||||||
|
|
||||||
|
### So, What can it do? ###
|
||||||
|
You can instruct Magallanes to deploy your code to all the servers you want (via rsync over ssh),
|
||||||
|
and run tasks for that freshly deployed code.
|
||||||
|
|
||||||
|
### How can I install it via composer? ###
|
||||||
|
|
||||||
### Installing
|
|
||||||
Simply add the following dependency to your project’s composer.json file:
|
Simply add the following dependency to your project’s composer.json file:
|
||||||
|
|
||||||
```json
|
```js
|
||||||
"require": {
|
"require": {
|
||||||
"andres-montanez/magallanes": "^4.0"
|
// ...
|
||||||
|
"andres-montanez/magallanes": "1.0.*"
|
||||||
|
// ...
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
Finally you can use **Magallanes** from the vendor's bin:
|
Now tell we update the vendors:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ vendor/bin/mage version
|
$ php composer update
|
||||||
```
|
```
|
||||||
|
|
||||||
### Codename Discovery One
|
And finally we can use Magallanes from the vendor's bin:
|
||||||
Each new mayor version of **Magallanes** will have a codename (like Ubuntu), version 3 was _Nostromo_, and in the current version it is **_Discovery One_**, in homage to the spaceship from the ground breaking film *2001: A Space Odyssey (1968)*.
|
|
||||||
|
```bash
|
||||||
|
$ bin/mage version
|
||||||
|
```
|
||||||
|
|
||||||
|
### Can you give me some examples/ideas? ###
|
||||||
|
**Sure!**
|
||||||
|
Suppose you have a checkout of your app and you have to deploy it to four servers;
|
||||||
|
and after each deploy you have to run some boring tasks, like fixing file permissions, creating symlinks, etc.
|
||||||
|
You can define all this on Magallanes and with *just one command* you can do all this at once!
|
||||||
|
|
||||||
|
Like this:
|
||||||
|
```
|
||||||
|
$ mage deploy to:production
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### What's this sorcery?! ###
|
||||||
|
Easy boy. It's not sorcery, just some *technomagick*!
|
||||||
|
|
||||||
|
In Magallanes you define environments like *testing*, *staging*, or *production* like on the example above.
|
||||||
|
Then, on that environment, you can configure a setup specifying to which hosts you want to deploy and what tasks to run (*after*, *on*, and *before* deploying).
|
||||||
|
And you are done!
|
||||||
|
|
||||||
|
|
||||||
|
### This is awesome! Where can I learn more? ###
|
||||||
|
You can read the whole source code (naaah!); or checkout the documentation at: http://magephp.com
|
||||||
|
|
||||||
|
|
||||||
|
Enjoy your magic trip with **Magallanes** to the land of the easily deployable apps!!
|
||||||
|
36
bin/mage
36
bin/mage
@ -1,19 +1,29 @@
|
|||||||
#!/usr/bin/env php
|
#!/usr/bin/env php
|
||||||
<?php
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of the Magallanes package.
|
||||||
|
*
|
||||||
|
* (c) Andrés Montañez <andres@andresmontanez.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE
|
||||||
|
* file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
date_default_timezone_set('UTC');
|
date_default_timezone_set('UTC');
|
||||||
|
|
||||||
if (file_exists(__DIR__ . '/../../../autoload.php')) {
|
$baseDir = dirname(dirname(__FILE__));
|
||||||
require __DIR__ . '/../../../autoload.php';
|
|
||||||
} elseif (file_exists(__DIR__ . '/../vendor/autoload.php')) {
|
|
||||||
require __DIR__ . '/../vendor/autoload.php';
|
|
||||||
}
|
|
||||||
|
|
||||||
use Mage\MageApplication;
|
define('MAGALLANES_VERSION', '1.0.0');
|
||||||
|
define('MAGALLANES_DIRECTORY', $baseDir);
|
||||||
|
|
||||||
try {
|
// Preload
|
||||||
$mage = new MageApplication('.mage.yml');
|
require_once $baseDir . '/Mage/spyc.php';
|
||||||
$mage->run();
|
require_once $baseDir . '/Mage/Autoload.php';
|
||||||
} catch (Exception $exception) {
|
spl_autoload_register(array('Mage\\Autoload', 'autoload'));
|
||||||
printf('Error: %s' . PHP_EOL, $exception->getMessage());
|
|
||||||
exit(9);
|
// Clean arguments
|
||||||
}
|
array_shift($argv);
|
||||||
|
|
||||||
|
// Run Magallanes
|
||||||
|
$console = new Mage\Console;
|
||||||
|
$console->run($argv);
|
||||||
|
@ -1,49 +1,14 @@
|
|||||||
{
|
{
|
||||||
"name": "hauke68/magallanes",
|
"name": "andres-montanez/magallanes",
|
||||||
"description": "The Deployment Tool for PHP Applications",
|
"description": "A Deployment Tool for PHP Applications",
|
||||||
"homepage": "https://magephp.com",
|
"homepage": "http://magephp.com",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"keywords": ["deployment"],
|
"keywords": ["deployment"],
|
||||||
"authors": [
|
"require": {
|
||||||
{
|
"php": ">=5.3"
|
||||||
"name": "Andrés Montañez",
|
|
||||||
"email": "andresmontanez@gmail.com"
|
|
||||||
},
|
},
|
||||||
{
|
"bin": [
|
||||||
"name": "Hauke Zühl",
|
"bin/mage"
|
||||||
"email": "hzuehl@web.de"
|
]
|
||||||
}
|
|
||||||
],
|
|
||||||
"require": {
|
|
||||||
"php": "^7.2.5",
|
|
||||||
"monolog/monolog": "~1.11||^2.0",
|
|
||||||
"symfony/console": "^5.0",
|
|
||||||
"symfony/filesystem": "^5.0",
|
|
||||||
"symfony/event-dispatcher": "^5.0",
|
|
||||||
"symfony/finder": "^5.0",
|
|
||||||
"symfony/yaml": "^5.0",
|
|
||||||
"symfony/process": "^5.0"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"phpunit/phpunit": "^7.0",
|
|
||||||
"satooshi/php-coveralls": "^2.0"
|
|
||||||
},
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"Mage\\": "src/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"autoload-dev": {
|
|
||||||
"psr-4": {
|
|
||||||
"Mage\\Tests\\": "tests/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"bin": ["bin/mage"],
|
|
||||||
"extra": {
|
|
||||||
"branch-alias": {
|
|
||||||
"dev-master": "4.0.x-dev",
|
|
||||||
"dev-discovery-one": "4.x-dev"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
59
docs/commands.txt
Normal file
59
docs/commands.txt
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
### List of Commands ###
|
||||||
|
|
||||||
|
# Installs Magallanes on the system
|
||||||
|
sudo mage install
|
||||||
|
|
||||||
|
# Displays Magallanes version
|
||||||
|
mage version
|
||||||
|
|
||||||
|
# Creats a Magallanes instance configuration
|
||||||
|
mage init
|
||||||
|
|
||||||
|
# Creates a compiled version of Magallanes using phar
|
||||||
|
mage compile
|
||||||
|
|
||||||
|
# Upgrades Magallanes itself
|
||||||
|
mage upgrade
|
||||||
|
|
||||||
|
# Add a new Environment configuration
|
||||||
|
mage add environment --name=production
|
||||||
|
|
||||||
|
# Add a new Environment configuration with releases enabled
|
||||||
|
mage add environment --name=production --enableReleases
|
||||||
|
|
||||||
|
# Performs a SCM Update, if configured
|
||||||
|
mage update
|
||||||
|
|
||||||
|
# Deploys Application to Production environment
|
||||||
|
mage deploy to:production
|
||||||
|
|
||||||
|
# Deploys Application to Production environment, overriding the current release
|
||||||
|
mage deploy to:production --overrideRelease
|
||||||
|
|
||||||
|
# Locks deployment to Production environment
|
||||||
|
mage lock to:production
|
||||||
|
|
||||||
|
# Unlocks deployment to Production environment
|
||||||
|
mage unlock to:production
|
||||||
|
|
||||||
|
# Lists all Releases on the Production environment
|
||||||
|
mage releases list to:production
|
||||||
|
|
||||||
|
# Rollback to the last Release on the Production environment
|
||||||
|
mage releases rollback to:production
|
||||||
|
mage releases rollback --release=0 to:production
|
||||||
|
|
||||||
|
# Rollback to the first, second, or thrith Release before the current Release on the Production environment
|
||||||
|
mage releases rollback --release=-1 to:production
|
||||||
|
mage releases rollback --release=-2 to:production
|
||||||
|
mage releases rollback --release=-3 to:production
|
||||||
|
|
||||||
|
# Rollback to a specific Release on the Production environment
|
||||||
|
# mage releases rollback --release=20120101172148 to:production
|
||||||
|
|
||||||
|
|
||||||
|
### List of UPCOMING Commands ###
|
||||||
|
# mage config add host s05.example.com to:[production]
|
||||||
|
# mage config git git://github.com/andres-montanez/Zend-Framework-Twig-example-app.git
|
||||||
|
# mage config svn svn://example.com/repo
|
||||||
|
# mage task:deployment/rsync to:production
|
@ -1,19 +0,0 @@
|
|||||||
version: '2'
|
|
||||||
services:
|
|
||||||
php5:
|
|
||||||
container_name: mage-php5
|
|
||||||
build: ./php5
|
|
||||||
volumes:
|
|
||||||
- ../../:/home/magephp
|
|
||||||
|
|
||||||
php7.0:
|
|
||||||
container_name: mage-php7.0
|
|
||||||
build: ./php7.0
|
|
||||||
volumes:
|
|
||||||
- ../../:/home/magephp
|
|
||||||
|
|
||||||
php7.1:
|
|
||||||
container_name: mage-php7.1
|
|
||||||
build: ./php7.1
|
|
||||||
volumes:
|
|
||||||
- ../../:/home/magephp
|
|
@ -1,9 +0,0 @@
|
|||||||
FROM ubuntu:14.04
|
|
||||||
|
|
||||||
RUN apt-get update && apt-get upgrade -y
|
|
||||||
RUN apt-get install -y vim curl git unzip
|
|
||||||
RUN apt-get install -y php5-cli php5-curl
|
|
||||||
|
|
||||||
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/bin/ --filename=composer
|
|
||||||
|
|
||||||
WORKDIR /home/magephp
|
|
@ -1,9 +0,0 @@
|
|||||||
FROM ubuntu:16.04
|
|
||||||
|
|
||||||
RUN apt-get update && apt-get upgrade -y
|
|
||||||
RUN apt-get install -y vim curl git unzip
|
|
||||||
RUN apt-get install -y php7.0-cli php-zip php7.0-curl php7.0-xml
|
|
||||||
|
|
||||||
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/bin/ --filename=composer
|
|
||||||
|
|
||||||
WORKDIR /home/magephp
|
|
@ -1,9 +0,0 @@
|
|||||||
FROM ubuntu:17.10
|
|
||||||
|
|
||||||
RUN apt-get update && apt-get upgrade -y
|
|
||||||
RUN apt-get install -y vim curl git unzip
|
|
||||||
RUN apt-get install -y php7.1-cli php-zip php7.1-curl php7.1-xml php7.1-mbstring
|
|
||||||
|
|
||||||
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/bin/ --filename=composer
|
|
||||||
|
|
||||||
WORKDIR /home/magephp
|
|
@ -1,31 +0,0 @@
|
|||||||
magephp:
|
|
||||||
environments:
|
|
||||||
production:
|
|
||||||
user: app
|
|
||||||
branch: test
|
|
||||||
from: ./
|
|
||||||
host_path: /var/www/test
|
|
||||||
releases: 4
|
|
||||||
exclude:
|
|
||||||
- vendor
|
|
||||||
- app/cache
|
|
||||||
- app/log
|
|
||||||
- web/app_dev.php
|
|
||||||
hosts:
|
|
||||||
- webserver1
|
|
||||||
- webserver2
|
|
||||||
- webserver3
|
|
||||||
pre-deploy:
|
|
||||||
- git/update
|
|
||||||
- composer/install
|
|
||||||
- composer/generate-autoload
|
|
||||||
on-deploy:
|
|
||||||
- symfony/cache-warmup: { env: 'prod' }
|
|
||||||
- symfony/assets-install: { env: 'prod' }
|
|
||||||
- symfony/assetic-dump: { env: 'prod' }
|
|
||||||
on-release:
|
|
||||||
post-release:
|
|
||||||
post-deploy:
|
|
||||||
- magic
|
|
||||||
custom_tasks:
|
|
||||||
- App\Deployment\MagicTask
|
|
40
docs/example-config/.mage/config/environment/production.yml
Normal file
40
docs/example-config/.mage/config/environment/production.yml
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#production
|
||||||
|
deployment:
|
||||||
|
user: root
|
||||||
|
from: ./
|
||||||
|
# source:
|
||||||
|
# type: git
|
||||||
|
# repository: git://github.com/andres-montanez/Zend-Framework-Twig-example-app.git
|
||||||
|
# from: production
|
||||||
|
# temporal: /tmp/myAppClone
|
||||||
|
to: /var/www/vhosts/example.com/www
|
||||||
|
excludes:
|
||||||
|
- application/data/cache/twig/*
|
||||||
|
releases:
|
||||||
|
enabled: true
|
||||||
|
max: 5
|
||||||
|
symlink: current
|
||||||
|
directory: releases
|
||||||
|
hosts:
|
||||||
|
s01.example.com:22:
|
||||||
|
deployment:
|
||||||
|
user: nobody
|
||||||
|
s02.example.com:
|
||||||
|
deployment:
|
||||||
|
user: toor
|
||||||
|
to: /home/web/public
|
||||||
|
releases:
|
||||||
|
max: 10
|
||||||
|
tasks:
|
||||||
|
on-deploy:
|
||||||
|
- privileges
|
||||||
|
- s03.example.com
|
||||||
|
tasks:
|
||||||
|
pre-deploy:
|
||||||
|
- scm/update
|
||||||
|
on-deploy:
|
||||||
|
# - symfony2/cache-warmup: {env: prod}
|
||||||
|
- privileges
|
||||||
|
- sampleTask
|
||||||
|
- sampleTaskRollbackAware
|
||||||
|
#post-deploy:
|
31
docs/example-config/.mage/config/environment/staging.yml
Normal file
31
docs/example-config/.mage/config/environment/staging.yml
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#staging
|
||||||
|
deployment:
|
||||||
|
user: root
|
||||||
|
from: ./
|
||||||
|
to: /var/www/
|
||||||
|
scm:
|
||||||
|
branch: master
|
||||||
|
releases:
|
||||||
|
enabled: true
|
||||||
|
max: 5
|
||||||
|
symlink: current
|
||||||
|
directory: releases
|
||||||
|
hosts:
|
||||||
|
- localhost
|
||||||
|
# - dbserver
|
||||||
|
tasks:
|
||||||
|
pre-deploy:
|
||||||
|
- sampleTask
|
||||||
|
# - failTask
|
||||||
|
- scm/update
|
||||||
|
on-deploy:
|
||||||
|
- privileges
|
||||||
|
- sampleTask
|
||||||
|
- sampleTaskRollbackAware
|
||||||
|
- taskWithParameters:
|
||||||
|
booleanOption: true
|
||||||
|
- taskWithParameters
|
||||||
|
post-release:
|
||||||
|
# - sampleTask
|
||||||
|
post-deploy:
|
||||||
|
- sampleTask
|
8
docs/example-config/.mage/config/general.yml
Normal file
8
docs/example-config/.mage/config/general.yml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#general settings
|
||||||
|
name: My fantastic App
|
||||||
|
email: andresmontanez@gmail.com
|
||||||
|
notifications: true
|
||||||
|
logging: true
|
||||||
|
scm:
|
||||||
|
type: git
|
||||||
|
url: git://github.com/andres-montanez/Zend-Framework-Twig-example-app.git
|
1
docs/example-config/.mage/logs/.gitignore
vendored
Normal file
1
docs/example-config/.mage/logs/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
log-*
|
17
docs/example-config/.mage/tasks/FailTask.php
Normal file
17
docs/example-config/.mage/tasks/FailTask.php
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
namespace Task;
|
||||||
|
|
||||||
|
use Mage\Task\AbstractTask;
|
||||||
|
|
||||||
|
class FailTask extends AbstractTask
|
||||||
|
{
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'A Failing Task';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
20
docs/example-config/.mage/tasks/Permissions.php
Normal file
20
docs/example-config/.mage/tasks/Permissions.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
namespace Task;
|
||||||
|
|
||||||
|
use Mage\Task\AbstractTask;
|
||||||
|
|
||||||
|
class Permissions extends AbstractTask
|
||||||
|
{
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'Fixing file permissions';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
$command = 'chmod 755 . -R';
|
||||||
|
$result = $this->runCommandRemote($command);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
20
docs/example-config/.mage/tasks/Privileges.php
Normal file
20
docs/example-config/.mage/tasks/Privileges.php
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
namespace Task;
|
||||||
|
|
||||||
|
use Mage\Task\AbstractTask;
|
||||||
|
|
||||||
|
class Privileges extends AbstractTask
|
||||||
|
{
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'Fixing file privileges';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
$command = 'chown 33:33 . -R';
|
||||||
|
$result = $this->runCommandRemote($command);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
17
docs/example-config/.mage/tasks/SampleTask.php
Normal file
17
docs/example-config/.mage/tasks/SampleTask.php
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
namespace Task;
|
||||||
|
|
||||||
|
use Mage\Task\AbstractTask;
|
||||||
|
|
||||||
|
class SampleTask extends AbstractTask
|
||||||
|
{
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'A Sample Task';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
22
docs/example-config/.mage/tasks/SampleTaskRollbackAware.php
Normal file
22
docs/example-config/.mage/tasks/SampleTaskRollbackAware.php
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
namespace Task;
|
||||||
|
|
||||||
|
use Mage\Task\AbstractTask;
|
||||||
|
use Mage\Task\Releases\RollbackAware;
|
||||||
|
|
||||||
|
class SampleTaskRollbackAware extends AbstractTask implements RollbackAware
|
||||||
|
{
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
if ($this->inRollback()) {
|
||||||
|
return 'A Sample Task aware of rollbacks [in rollback]';
|
||||||
|
} else {
|
||||||
|
return 'A Sample Task aware of rollbacks [not in rollback]';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
25
docs/example-config/.mage/tasks/TaskWithParameters.php
Normal file
25
docs/example-config/.mage/tasks/TaskWithParameters.php
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
namespace Task;
|
||||||
|
|
||||||
|
use Mage\Task\AbstractTask;
|
||||||
|
|
||||||
|
class TaskWithParameters extends AbstractTask
|
||||||
|
{
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
$booleanOption = $this->getParameter('booleanOption', false);
|
||||||
|
if ($booleanOption) {
|
||||||
|
return 'A Sample Task With Parameters [booleanOption=true]';
|
||||||
|
} else {
|
||||||
|
return 'A Sample Task With Parameters [booleanOption=false]';
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
//throw new Mage_Task_SkipException;
|
||||||
|
//return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -1,37 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
|
|
||||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.1/phpunit.xsd"
|
|
||||||
backupGlobals="false"
|
|
||||||
colors="true"
|
|
||||||
bootstrap="vendor/autoload.php"
|
|
||||||
>
|
|
||||||
<php>
|
|
||||||
<ini name="error_reporting" value="-1" />
|
|
||||||
<ini name="intl.default_locale" value="en" />
|
|
||||||
<ini name="intl.error_level" value="0" />
|
|
||||||
<ini name="memory_limit" value="-1" />
|
|
||||||
</php>
|
|
||||||
|
|
||||||
<testsuites>
|
|
||||||
<testsuite name="Magallanes Test Suite">
|
|
||||||
<directory>./tests/</directory>
|
|
||||||
</testsuite>
|
|
||||||
</testsuites>
|
|
||||||
|
|
||||||
<groups>
|
|
||||||
<exclude>
|
|
||||||
<group>benchmark</group>
|
|
||||||
<group>intl-data</group>
|
|
||||||
</exclude>
|
|
||||||
</groups>
|
|
||||||
|
|
||||||
<filter>
|
|
||||||
<whitelist>
|
|
||||||
<directory>./src/</directory>
|
|
||||||
<exclude>
|
|
||||||
<directory>./tests/</directory>
|
|
||||||
</exclude>
|
|
||||||
</whitelist>
|
|
||||||
</filter>
|
|
||||||
</phpunit>
|
|
@ -1,81 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* This file is part of the Magallanes package.
|
|
||||||
*
|
|
||||||
* (c) Andrés Montañez <andres@andresmontanez.com>
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Mage\Command;
|
|
||||||
|
|
||||||
use Mage\MageApplication;
|
|
||||||
use Mage\Utils;
|
|
||||||
use Mage\Runtime\Runtime;
|
|
||||||
use Psr\Log\LogLevel;
|
|
||||||
use Symfony\Component\Console\Command\Command;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abstract base class for Magallanes Commands
|
|
||||||
*
|
|
||||||
* @author Andrés Montañez <andresmontanez@gmail.com>
|
|
||||||
*/
|
|
||||||
abstract class AbstractCommand extends Command
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var int
|
|
||||||
*/
|
|
||||||
protected $statusCode = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Runtime Current Runtime instance
|
|
||||||
*/
|
|
||||||
protected $runtime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the Runtime configuration
|
|
||||||
*
|
|
||||||
* @param Runtime $runtime Runtime container
|
|
||||||
* @return AbstractCommand
|
|
||||||
*/
|
|
||||||
public function setRuntime(Runtime $runtime)
|
|
||||||
{
|
|
||||||
$this->runtime = $runtime;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Logs a message
|
|
||||||
*
|
|
||||||
* @param string $message
|
|
||||||
* @param string $level
|
|
||||||
*/
|
|
||||||
public function log($message, $level = LogLevel::DEBUG)
|
|
||||||
{
|
|
||||||
$this->runtime->log($message, $level);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the Human friendly Stage name
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
protected function getStageName()
|
|
||||||
{
|
|
||||||
$utils = new Utils();
|
|
||||||
return $utils->getStageName($this->runtime->getStage());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Requires the configuration to be loaded
|
|
||||||
*/
|
|
||||||
protected function requireConfig()
|
|
||||||
{
|
|
||||||
$app = $this->getApplication();
|
|
||||||
if ($app instanceof MageApplication) {
|
|
||||||
$app->configure();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,56 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* This file is part of the Magallanes package.
|
|
||||||
*
|
|
||||||
* (c) Andrés Montañez <andres@andresmontanez.com>
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Mage\Command\BuiltIn\Config;
|
|
||||||
|
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
|
||||||
use Mage\Command\AbstractCommand;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Command for Dumping the Configuration
|
|
||||||
*
|
|
||||||
* @author Andrés Montañez <andresmontanez@gmail.com>
|
|
||||||
*/
|
|
||||||
class DumpCommand extends AbstractCommand
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Configure the Command
|
|
||||||
*/
|
|
||||||
protected function configure()
|
|
||||||
{
|
|
||||||
$this
|
|
||||||
->setName('config:dump')
|
|
||||||
->setDescription('Dumps the Magallanes configuration')
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the Command
|
|
||||||
*
|
|
||||||
* @param InputInterface $input
|
|
||||||
* @param OutputInterface $output
|
|
||||||
* @return int|mixed
|
|
||||||
*/
|
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
|
||||||
{
|
|
||||||
$this->requireConfig();
|
|
||||||
|
|
||||||
$output->writeln('Starting <fg=blue>Magallanes</>');
|
|
||||||
$output->writeln('');
|
|
||||||
|
|
||||||
$output->writeln(sprintf('<comment>%s</comment>', var_export($this->runtime->getConfiguration(), true)));
|
|
||||||
|
|
||||||
$output->writeln('');
|
|
||||||
$output->writeln('Finished <fg=blue>Magallanes</>');
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,71 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* This file is part of the Magallanes package.
|
|
||||||
*
|
|
||||||
* (c) Andrés Montañez <andres@andresmontanez.com>
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Mage\Command\BuiltIn\Config;
|
|
||||||
|
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
|
||||||
use Symfony\Component\Console\Helper\Table;
|
|
||||||
use Mage\Command\AbstractCommand;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Command for listing all the Environments
|
|
||||||
*
|
|
||||||
* @author Andrés Montañez <andresmontanez@gmail.com>
|
|
||||||
*/
|
|
||||||
class EnvironmentsCommand extends AbstractCommand
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Configure the Command
|
|
||||||
*/
|
|
||||||
protected function configure()
|
|
||||||
{
|
|
||||||
$this
|
|
||||||
->setName('config:environments')
|
|
||||||
->setDescription('List all Magallanes configured Environments')
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the Command
|
|
||||||
*
|
|
||||||
* @param InputInterface $input
|
|
||||||
* @param OutputInterface $output
|
|
||||||
* @return int|mixed
|
|
||||||
*/
|
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
|
||||||
{
|
|
||||||
$this->requireConfig();
|
|
||||||
|
|
||||||
$output->writeln('Starting <fg=blue>Magallanes</>');
|
|
||||||
$output->writeln('');
|
|
||||||
|
|
||||||
$table = new Table($output);
|
|
||||||
$table->setHeaders(['Environment', 'User', 'Branch', 'Hosts']);
|
|
||||||
|
|
||||||
$configuration = $this->runtime->getConfigOption('environments');
|
|
||||||
foreach ($configuration as $environment => $config) {
|
|
||||||
$row = [$environment];
|
|
||||||
|
|
||||||
$row[] = (isset($config['user']) ? $config['user'] : '-');
|
|
||||||
$row[] = (isset($config['branch']) ? $config['branch'] : '-');
|
|
||||||
$row[] = (isset($config['hosts']) ? implode(PHP_EOL, $config['hosts']) : '-');
|
|
||||||
|
|
||||||
$table->addRow($row);
|
|
||||||
}
|
|
||||||
|
|
||||||
$table->render();
|
|
||||||
|
|
||||||
$output->writeln('');
|
|
||||||
$output->writeln('Finished <fg=blue>Magallanes</>');
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,245 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* This file is part of the Magallanes package.
|
|
||||||
*
|
|
||||||
* (c) Andrés Montañez <andres@andresmontanez.com>
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Mage\Command\BuiltIn;
|
|
||||||
|
|
||||||
use Mage\Deploy\Strategy\StrategyInterface;
|
|
||||||
use Mage\Runtime\Exception\RuntimeException;
|
|
||||||
use Mage\Runtime\Runtime;
|
|
||||||
use Mage\Task\ExecuteOnRollbackInterface;
|
|
||||||
use Mage\Task\AbstractTask;
|
|
||||||
use Mage\Task\Exception\ErrorException;
|
|
||||||
use Mage\Task\Exception\SkipException;
|
|
||||||
use Mage\Task\TaskFactory;
|
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
|
||||||
use Symfony\Component\Console\Input\InputArgument;
|
|
||||||
use Symfony\Component\Console\Input\InputOption;
|
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
|
||||||
use Mage\Command\AbstractCommand;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Deployment Command
|
|
||||||
*
|
|
||||||
* @author Andrés Montañez <andresmontanez@gmail.com>
|
|
||||||
*/
|
|
||||||
class DeployCommand extends AbstractCommand
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var TaskFactory
|
|
||||||
*/
|
|
||||||
protected $taskFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configure the Command
|
|
||||||
*/
|
|
||||||
protected function configure()
|
|
||||||
{
|
|
||||||
$this
|
|
||||||
->setName('deploy')
|
|
||||||
->setDescription('Deploy code to hosts')
|
|
||||||
->addArgument('environment', InputArgument::REQUIRED, 'Name of the environment to deploy to')
|
|
||||||
->addOption('branch', null, InputOption::VALUE_REQUIRED, 'Force to switch to a branch other than the one defined', false)
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the Command
|
|
||||||
*
|
|
||||||
* @param InputInterface $input
|
|
||||||
* @param OutputInterface $output
|
|
||||||
* @return integer
|
|
||||||
*/
|
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
|
||||||
{
|
|
||||||
$this->requireConfig();
|
|
||||||
|
|
||||||
$output->writeln('Starting <fg=blue>Magallanes</>');
|
|
||||||
$output->writeln('');
|
|
||||||
|
|
||||||
try {
|
|
||||||
$this->runtime->setEnvironment($input->getArgument('environment'));
|
|
||||||
|
|
||||||
$strategy = $this->runtime->guessStrategy();
|
|
||||||
$this->taskFactory = new TaskFactory($this->runtime);
|
|
||||||
|
|
||||||
$output->writeln(sprintf(' Environment: <fg=green>%s</>', $this->runtime->getEnvironment()));
|
|
||||||
$this->log(sprintf('Environment: %s', $this->runtime->getEnvironment()));
|
|
||||||
|
|
||||||
if ($this->runtime->getEnvOption('releases', false)) {
|
|
||||||
$this->runtime->generateReleaseId();
|
|
||||||
$output->writeln(sprintf(' Release ID: <fg=green>%s</>', $this->runtime->getReleaseId()));
|
|
||||||
$this->log(sprintf('Release ID: %s', $this->runtime->getReleaseId()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->runtime->getConfigOption('log_file', false)) {
|
|
||||||
$output->writeln(sprintf(' Logfile: <fg=green>%s</>', $this->runtime->getConfigOption('log_file')));
|
|
||||||
}
|
|
||||||
|
|
||||||
$output->writeln(sprintf(' Strategy: <fg=green>%s</>', $strategy->getName()));
|
|
||||||
|
|
||||||
if ($input->getOption('branch') !== false) {
|
|
||||||
$this->runtime->setEnvOption('branch', $input->getOption('branch'));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->runtime->getEnvOption('branch', false)) {
|
|
||||||
$output->writeln(sprintf(' Branch: <fg=green>%s</>', $this->runtime->getEnvOption('branch')));
|
|
||||||
}
|
|
||||||
|
|
||||||
$output->writeln('');
|
|
||||||
$this->runDeployment($output, $strategy);
|
|
||||||
} catch (RuntimeException $exception) {
|
|
||||||
$output->writeln('');
|
|
||||||
$output->writeln(sprintf('<error>%s</error>', $exception->getMessage()));
|
|
||||||
$output->writeln('');
|
|
||||||
$this->statusCode = 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
$output->writeln('Finished <fg=blue>Magallanes</>');
|
|
||||||
|
|
||||||
return $this->statusCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Run the Deployment Process
|
|
||||||
*
|
|
||||||
* @param OutputInterface $output
|
|
||||||
* @param StrategyInterface $strategy
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
protected function runDeployment(OutputInterface $output, StrategyInterface $strategy)
|
|
||||||
{
|
|
||||||
// Run "Pre Deploy" Tasks
|
|
||||||
$this->runtime->setStage(Runtime::PRE_DEPLOY);
|
|
||||||
if (!$this->runTasks($output, $strategy->getPreDeployTasks())) {
|
|
||||||
throw $this->getException();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run "On Deploy" Tasks
|
|
||||||
$this->runtime->setStage(Runtime::ON_DEPLOY);
|
|
||||||
$this->runOnHosts($output, $strategy->getOnDeployTasks());
|
|
||||||
|
|
||||||
// Run "On Release" Tasks
|
|
||||||
$this->runtime->setStage(Runtime::ON_RELEASE);
|
|
||||||
$this->runOnHosts($output, $strategy->getOnReleaseTasks());
|
|
||||||
|
|
||||||
// Run "Post Release" Tasks
|
|
||||||
$this->runtime->setStage(Runtime::POST_RELEASE);
|
|
||||||
$this->runOnHosts($output, $strategy->getPostReleaseTasks());
|
|
||||||
|
|
||||||
// Run "Post Deploy" Tasks
|
|
||||||
$this->runtime->setStage(Runtime::POST_DEPLOY);
|
|
||||||
if (!$this->runTasks($output, $strategy->getPostDeployTasks())) {
|
|
||||||
throw $this->getException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function runOnHosts(OutputInterface $output, $tasks)
|
|
||||||
{
|
|
||||||
$hosts = $this->runtime->getEnvOption('hosts');
|
|
||||||
if (!is_array($hosts) && !$hosts instanceof \Countable) {
|
|
||||||
$hosts = [];
|
|
||||||
}
|
|
||||||
if (count($hosts) == 0) {
|
|
||||||
$output->writeln(sprintf(' No hosts defined, skipping %s tasks', $this->getStageName()));
|
|
||||||
$output->writeln('');
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($hosts as $host) {
|
|
||||||
$this->runtime->setWorkingHost($host);
|
|
||||||
if (!$this->runTasks($output, $tasks)) {
|
|
||||||
$this->runtime->setWorkingHost(null);
|
|
||||||
throw $this->getException();
|
|
||||||
}
|
|
||||||
$this->runtime->setWorkingHost(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runs all the tasks
|
|
||||||
*
|
|
||||||
* @param OutputInterface $output
|
|
||||||
* @param $tasks
|
|
||||||
* @return bool
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
protected function runTasks(OutputInterface $output, $tasks)
|
|
||||||
{
|
|
||||||
if (count($tasks) == 0) {
|
|
||||||
$output->writeln(sprintf(' No tasks defined for <fg=black;options=bold>%s</> stage', $this->getStageName()));
|
|
||||||
$output->writeln('');
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->runtime->getHostName() !== null) {
|
|
||||||
$output->writeln(sprintf(' Starting <fg=black;options=bold>%s</> tasks on host <fg=black;options=bold>%s</>:', $this->getStageName(), $this->runtime->getHostName()));
|
|
||||||
} else {
|
|
||||||
$output->writeln(sprintf(' Starting <fg=black;options=bold>%s</> tasks:', $this->getStageName()));
|
|
||||||
}
|
|
||||||
|
|
||||||
$totalTasks = count($tasks);
|
|
||||||
$succeededTasks = 0;
|
|
||||||
|
|
||||||
foreach ($tasks as $taskName) {
|
|
||||||
/** @var AbstractTask $task */
|
|
||||||
$task = $this->taskFactory->get($taskName);
|
|
||||||
$output->write(sprintf(' Running <fg=magenta>%s</> ... ', $task->getDescription()));
|
|
||||||
$this->log(sprintf('Running task %s (%s)', $task->getDescription(), $task->getName()));
|
|
||||||
|
|
||||||
if ($this->runtime->inRollback() && !$task instanceof ExecuteOnRollbackInterface) {
|
|
||||||
$succeededTasks++;
|
|
||||||
$output->writeln('<fg=yellow>SKIPPED</>');
|
|
||||||
$this->log(sprintf('Task %s (%s) finished with SKIPPED, it was in a Rollback', $task->getDescription(), $task->getName()));
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
if ($task->execute()) {
|
|
||||||
$succeededTasks++;
|
|
||||||
$output->writeln('<fg=green>OK</>');
|
|
||||||
$this->log(sprintf('Task %s (%s) finished with OK', $task->getDescription(), $task->getName()));
|
|
||||||
} else {
|
|
||||||
$output->writeln('<fg=red>FAIL</>');
|
|
||||||
$this->statusCode = 180;
|
|
||||||
$this->log(sprintf('Task %s (%s) finished with FAIL', $task->getDescription(), $task->getName()));
|
|
||||||
}
|
|
||||||
} catch (SkipException $exception) {
|
|
||||||
$succeededTasks++;
|
|
||||||
$output->writeln('<fg=yellow>SKIPPED</>');
|
|
||||||
$this->log(sprintf('Task %s (%s) finished with SKIPPED, thrown SkipException', $task->getDescription(), $task->getName()));
|
|
||||||
} catch (ErrorException $exception) {
|
|
||||||
$output->writeln(sprintf('<fg=red>ERROR</> [%s]', $exception->getTrimmedMessage()));
|
|
||||||
$this->log(sprintf('Task %s (%s) finished with FAIL, with Error "%s"', $task->getDescription(), $task->getName(), $exception->getMessage()));
|
|
||||||
$this->statusCode = 190;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->statusCode !== 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$alertColor = 'red';
|
|
||||||
if ($succeededTasks == $totalTasks) {
|
|
||||||
$alertColor = 'green';
|
|
||||||
}
|
|
||||||
|
|
||||||
$output->writeln(sprintf(' Finished <fg=%s>%d/%d</> tasks for <fg=black;options=bold>%s</>.', $alertColor, $succeededTasks, $totalTasks, $this->getStageName()));
|
|
||||||
$output->writeln('');
|
|
||||||
|
|
||||||
return ($succeededTasks == $totalTasks);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exception for halting the the current process
|
|
||||||
*/
|
|
||||||
protected function getException()
|
|
||||||
{
|
|
||||||
return new RuntimeException(sprintf('Stage "%s" did not finished successfully, halting command.', $this->getStageName()), 50);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,151 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* This file is part of the Magallanes package.
|
|
||||||
*
|
|
||||||
* (c) Andrés Montañez <andres@andresmontanez.com>
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Mage\Command\BuiltIn\Releases;
|
|
||||||
|
|
||||||
use Mage\Utils;
|
|
||||||
use Mage\Runtime\Exception\RuntimeException;
|
|
||||||
use Symfony\Component\Process\Process;
|
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
|
||||||
use Symfony\Component\Console\Input\InputArgument;
|
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
|
||||||
use Mage\Command\AbstractCommand;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Command for Listing all Releases
|
|
||||||
*
|
|
||||||
* @author Andrés Montañez <andresmontanez@gmail.com>
|
|
||||||
*/
|
|
||||||
class ListCommand extends AbstractCommand
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var int
|
|
||||||
*/
|
|
||||||
protected $statusCode = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configure the Command
|
|
||||||
*/
|
|
||||||
protected function configure()
|
|
||||||
{
|
|
||||||
$this
|
|
||||||
->setName('releases:list')
|
|
||||||
->setDescription('List the releases on an environment')
|
|
||||||
->addArgument('environment', InputArgument::REQUIRED, 'Name of the environment to deploy to')
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the Command
|
|
||||||
*
|
|
||||||
* @param InputInterface $input
|
|
||||||
* @param OutputInterface $output
|
|
||||||
* @return int|mixed
|
|
||||||
*/
|
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
|
||||||
{
|
|
||||||
$this->requireConfig();
|
|
||||||
|
|
||||||
$utils = new Utils();
|
|
||||||
$output->writeln('Starting <fg=blue>Magallanes</>');
|
|
||||||
$output->writeln('');
|
|
||||||
|
|
||||||
try {
|
|
||||||
$this->runtime->setEnvironment($input->getArgument('environment'));
|
|
||||||
|
|
||||||
if (!$this->runtime->getEnvOption('releases', false)) {
|
|
||||||
throw new RuntimeException('Releases are not enabled', 70);
|
|
||||||
}
|
|
||||||
|
|
||||||
$output->writeln(sprintf(' Environment: <fg=green>%s</>', $this->runtime->getEnvironment()));
|
|
||||||
$this->log(sprintf('Environment: %s', $this->runtime->getEnvironment()));
|
|
||||||
|
|
||||||
if ($this->runtime->getConfigOption('log_file', false)) {
|
|
||||||
$output->writeln(sprintf(' Logfile: <fg=green>%s</>', $this->runtime->getConfigOption('log_file')));
|
|
||||||
}
|
|
||||||
|
|
||||||
$output->writeln('');
|
|
||||||
|
|
||||||
$hosts = $this->runtime->getEnvOption('hosts');
|
|
||||||
if (!is_array($hosts) && !$hosts instanceof \Countable) {
|
|
||||||
$hosts = [];
|
|
||||||
}
|
|
||||||
if (count($hosts) == 0) {
|
|
||||||
$output->writeln('No hosts defined');
|
|
||||||
$output->writeln('');
|
|
||||||
} else {
|
|
||||||
$hostPath = rtrim($this->runtime->getEnvOption('host_path'), '/');
|
|
||||||
|
|
||||||
foreach ($hosts as $host) {
|
|
||||||
$this->runtime->setWorkingHost($host);
|
|
||||||
|
|
||||||
// Get List of Releases
|
|
||||||
$cmdListReleases = sprintf('ls -1 %s/releases', $hostPath);
|
|
||||||
|
|
||||||
/** @var Process $process */
|
|
||||||
$process = $this->runtime->runRemoteCommand($cmdListReleases, false);
|
|
||||||
if (!$process->isSuccessful()) {
|
|
||||||
throw new RuntimeException(sprintf('Unable to retrieve releases from host "%s"', $host), 80);
|
|
||||||
}
|
|
||||||
|
|
||||||
$releases = [];
|
|
||||||
if (trim($process->getOutput()) != '') {
|
|
||||||
$releases = explode(PHP_EOL, trim($process->getOutput()));
|
|
||||||
rsort($releases);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count($releases) == 0) {
|
|
||||||
$output->writeln(sprintf(' No releases available on host <fg=black;options=bold>%s</>:', $host));
|
|
||||||
} else {
|
|
||||||
// Get Current Release
|
|
||||||
$cmdCurrentRelease = sprintf('readlink -f %s/current', $hostPath);
|
|
||||||
|
|
||||||
/** @var Process $process */
|
|
||||||
$process = $this->runtime->runRemoteCommand($cmdCurrentRelease, false);
|
|
||||||
if (!$process->isSuccessful()) {
|
|
||||||
throw new RuntimeException(sprintf('Unable to retrieve current release from host "%s"', $host), 85);
|
|
||||||
}
|
|
||||||
|
|
||||||
$currentReleaseId = explode('/', trim($process->getOutput()));
|
|
||||||
$currentReleaseId = $currentReleaseId[count($currentReleaseId) - 1];
|
|
||||||
|
|
||||||
$output->writeln(sprintf(' Releases on host <fg=black;options=bold>%s</>:', $host));
|
|
||||||
|
|
||||||
foreach ($releases as $releaseId) {
|
|
||||||
$releaseDate = $utils->getReleaseDate($releaseId);
|
|
||||||
|
|
||||||
$output->write(sprintf(' Release ID: <fg=magenta>%s</> - Date: <fg=black;options=bold>%s</> [%s]',
|
|
||||||
$releaseId,
|
|
||||||
$releaseDate->format('Y-m-d H:i:s'),
|
|
||||||
$utils->getTimeDiff($releaseDate)
|
|
||||||
));
|
|
||||||
|
|
||||||
if ($releaseId == $currentReleaseId) {
|
|
||||||
$output->writeln(' <fg=red;options=bold>[current]</>');
|
|
||||||
} else {
|
|
||||||
$output->writeln('');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->runtime->setWorkingHost(null);
|
|
||||||
$output->writeln('');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (RuntimeException $exception) {
|
|
||||||
$output->writeln(sprintf('<error>%s</error>', $exception->getMessage()));
|
|
||||||
$this->statusCode = $exception->getCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
$output->writeln('Finished <fg=blue>Magallanes</>');
|
|
||||||
|
|
||||||
return $this->statusCode;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,140 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* This file is part of the Magallanes package.
|
|
||||||
*
|
|
||||||
* (c) Andrés Montañez <andres@andresmontanez.com>
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Mage\Command\BuiltIn\Releases;
|
|
||||||
|
|
||||||
use Mage\Task\TaskFactory;
|
|
||||||
use Mage\Runtime\Exception\RuntimeException;
|
|
||||||
use Symfony\Component\Process\Process;
|
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
|
||||||
use Symfony\Component\Console\Input\InputArgument;
|
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
|
||||||
use Mage\Command\BuiltIn\DeployCommand;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Command for Rolling Back a Releases
|
|
||||||
*
|
|
||||||
* @author Andrés Montañez <andresmontanez@gmail.com>
|
|
||||||
*/
|
|
||||||
class RollbackCommand extends DeployCommand
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var int
|
|
||||||
*/
|
|
||||||
protected $statusCode = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configure the Command
|
|
||||||
*/
|
|
||||||
protected function configure()
|
|
||||||
{
|
|
||||||
$this
|
|
||||||
->setName('releases:rollback')
|
|
||||||
->setDescription('Rollback to a release on an environment')
|
|
||||||
->addArgument('environment', InputArgument::REQUIRED, 'Name of the environment to deploy to')
|
|
||||||
->addArgument('release', InputArgument::REQUIRED, 'The ID or the Index of the release to rollback to')
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the Command
|
|
||||||
*
|
|
||||||
* @param InputInterface $input
|
|
||||||
* @param OutputInterface $output
|
|
||||||
* @return int|mixed
|
|
||||||
*/
|
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
|
||||||
{
|
|
||||||
$this->requireConfig();
|
|
||||||
|
|
||||||
$output->writeln('Starting <fg=blue>Magallanes</>');
|
|
||||||
$output->writeln('');
|
|
||||||
|
|
||||||
try {
|
|
||||||
$this->runtime->setEnvironment($input->getArgument('environment'));
|
|
||||||
|
|
||||||
$strategy = $this->runtime->guessStrategy();
|
|
||||||
$this->taskFactory = new TaskFactory($this->runtime);
|
|
||||||
|
|
||||||
if (!$this->runtime->getEnvOption('releases', false)) {
|
|
||||||
throw new RuntimeException('Releases are not enabled', 70);
|
|
||||||
}
|
|
||||||
|
|
||||||
$releaseToRollback = $input->getArgument('release');
|
|
||||||
if (($releaseId = $this->checkReleaseAvailability($releaseToRollback)) === false) {
|
|
||||||
throw new RuntimeException(sprintf('Release "%s" is not available on all hosts', $releaseToRollback), 72);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->runtime->setReleaseId($releaseId)->setRollback(true);
|
|
||||||
|
|
||||||
$output->writeln(sprintf(' Environment: <fg=green>%s</>', $this->runtime->getEnvironment()));
|
|
||||||
$this->log(sprintf('Environment: %s', $this->runtime->getEnvironment()));
|
|
||||||
|
|
||||||
$output->writeln(sprintf(' Rollback to Release Id: <fg=green>%s</>', $this->runtime->getReleaseId()));
|
|
||||||
$this->log(sprintf('Release ID: %s', $this->runtime->getReleaseId()));
|
|
||||||
|
|
||||||
if ($this->runtime->getConfigOption('log_file', false)) {
|
|
||||||
$output->writeln(sprintf(' Logfile: <fg=green>%s</>', $this->runtime->getConfigOption('log_file')));
|
|
||||||
}
|
|
||||||
|
|
||||||
$output->writeln(sprintf(' Strategy: <fg=green>%s</>', $strategy->getName()));
|
|
||||||
|
|
||||||
$output->writeln('');
|
|
||||||
$this->runDeployment($output, $strategy);
|
|
||||||
} catch (RuntimeException $exception) {
|
|
||||||
$output->writeln(sprintf('<error>%s</error>', $exception->getMessage()));
|
|
||||||
$this->statusCode = $exception->getCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
$output->writeln('Finished <fg=blue>Magallanes</>');
|
|
||||||
|
|
||||||
return $this->statusCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the provided Release ID is available in all hosts
|
|
||||||
*
|
|
||||||
* @param string $releaseToRollback Release ID
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
protected function checkReleaseAvailability($releaseToRollback)
|
|
||||||
{
|
|
||||||
$hosts = $this->runtime->getEnvOption('hosts');
|
|
||||||
$hostPath = rtrim($this->runtime->getEnvOption('host_path'), '/');
|
|
||||||
|
|
||||||
$availableInHosts = 0;
|
|
||||||
foreach ($hosts as $host) {
|
|
||||||
$releases = [];
|
|
||||||
$this->runtime->setWorkingHost($host);
|
|
||||||
|
|
||||||
// Get List of Releases
|
|
||||||
$cmdListReleases = sprintf('ls -1 %s/releases', $hostPath);
|
|
||||||
|
|
||||||
/** @var Process $process */
|
|
||||||
$process = $this->runtime->runRemoteCommand($cmdListReleases, false);
|
|
||||||
if ($process->isSuccessful()) {
|
|
||||||
$releases = explode(PHP_EOL, trim($process->getOutput()));
|
|
||||||
rsort($releases);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (in_array($releaseToRollback, $releases)) {
|
|
||||||
$availableInHosts++;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->runtime->setWorkingHost(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($availableInHosts === count($hosts)) {
|
|
||||||
return $releaseToRollback;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* This file is part of the Magallanes package.
|
|
||||||
*
|
|
||||||
* (c) Andrés Montañez <andres@andresmontanez.com>
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Mage\Command\BuiltIn;
|
|
||||||
|
|
||||||
use Mage\Mage;
|
|
||||||
use Symfony\Component\Console\Input\InputInterface;
|
|
||||||
use Symfony\Component\Console\Output\OutputInterface;
|
|
||||||
use Mage\Command\AbstractCommand;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Version Command, return the current version of Magallanes
|
|
||||||
*
|
|
||||||
* @author Andrés Montañez <andresmontanez@gmail.com>
|
|
||||||
*/
|
|
||||||
class VersionCommand extends AbstractCommand
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Configure the Command
|
|
||||||
*/
|
|
||||||
protected function configure()
|
|
||||||
{
|
|
||||||
$this
|
|
||||||
->setName('version')
|
|
||||||
->setDescription('Get the version of Magallanes')
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes the Command
|
|
||||||
*
|
|
||||||
* @param InputInterface $input
|
|
||||||
* @param OutputInterface $output
|
|
||||||
* @return int
|
|
||||||
*/
|
|
||||||
protected function execute(InputInterface $input, OutputInterface $output)
|
|
||||||
{
|
|
||||||
$output->writeln(sprintf('Magallanes v%s [%s]', Mage::VERSION, Mage::CODENAME));
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,122 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* This file is part of the Magallanes package.
|
|
||||||
*
|
|
||||||
* (c) Andrés Montañez <andres@andresmontanez.com>
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Mage\Deploy\Strategy;
|
|
||||||
|
|
||||||
use Mage\Runtime\Exception\RuntimeException;
|
|
||||||
use Mage\Runtime\Runtime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Strategy for Deployment with Releases, using Tar and SCP
|
|
||||||
*
|
|
||||||
* @author Andrés Montañez <andresmontanez@gmail.com>
|
|
||||||
*/
|
|
||||||
class ReleasesStrategy implements StrategyInterface
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var Runtime
|
|
||||||
*/
|
|
||||||
protected $runtime;
|
|
||||||
|
|
||||||
public function getName()
|
|
||||||
{
|
|
||||||
return 'Releases';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setRuntime(Runtime $runtime)
|
|
||||||
{
|
|
||||||
$this->runtime = $runtime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getPreDeployTasks()
|
|
||||||
{
|
|
||||||
$this->checkStage(Runtime::PRE_DEPLOY);
|
|
||||||
$tasks = $this->runtime->getTasks();
|
|
||||||
|
|
||||||
if ($this->runtime->getBranch() && !$this->runtime->inRollback() && !in_array('git/change-branch', $tasks)) {
|
|
||||||
array_unshift($tasks, 'git/change-branch');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$this->runtime->inRollback() && !in_array('deploy/tar/prepare', $tasks)) {
|
|
||||||
array_push($tasks, 'deploy/tar/prepare');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $tasks;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getOnDeployTasks()
|
|
||||||
{
|
|
||||||
$this->checkStage(Runtime::ON_DEPLOY);
|
|
||||||
$tasks = $this->runtime->getTasks();
|
|
||||||
|
|
||||||
if (!$this->runtime->inRollback() && !in_array('deploy/tar/copy', $tasks)) {
|
|
||||||
array_unshift($tasks, 'deploy/tar/copy');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$this->runtime->inRollback() && !in_array('deploy/release/prepare', $tasks)) {
|
|
||||||
array_unshift($tasks, 'deploy/release/prepare');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $tasks;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getOnReleaseTasks()
|
|
||||||
{
|
|
||||||
$this->checkStage(Runtime::ON_RELEASE);
|
|
||||||
$tasks = $this->runtime->getTasks();
|
|
||||||
|
|
||||||
if (!in_array('deploy/release', $tasks)) {
|
|
||||||
array_unshift($tasks, 'deploy/release');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $tasks;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getPostReleaseTasks()
|
|
||||||
{
|
|
||||||
$this->checkStage(Runtime::POST_RELEASE);
|
|
||||||
$tasks = $this->runtime->getTasks();
|
|
||||||
|
|
||||||
if (!in_array('deploy/release/cleanup', $tasks)) {
|
|
||||||
array_unshift($tasks, 'deploy/release/cleanup');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $tasks;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getPostDeployTasks()
|
|
||||||
{
|
|
||||||
$this->checkStage(Runtime::POST_DEPLOY);
|
|
||||||
$tasks = $this->runtime->getTasks();
|
|
||||||
|
|
||||||
if (!$this->runtime->inRollback() && !in_array('deploy/tar/cleanup', $tasks)) {
|
|
||||||
array_unshift($tasks, 'deploy/tar/cleanup');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->runtime->getBranch() && !$this->runtime->inRollback() && !in_array('git/change-branch', $tasks)) {
|
|
||||||
array_push($tasks, 'git/change-branch');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $tasks;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check the runtime stage is correct
|
|
||||||
*
|
|
||||||
* @param $stage
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
private function checkStage($stage)
|
|
||||||
{
|
|
||||||
if ($this->runtime->getStage() !== $stage) {
|
|
||||||
throw new RuntimeException(sprintf('Invalid stage, got "%s" but expected "%"', $this->runtime->getStage(), $stage));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,96 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* This file is part of the Magallanes package.
|
|
||||||
*
|
|
||||||
* (c) Andrés Montañez <andres@andresmontanez.com>
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Mage\Deploy\Strategy;
|
|
||||||
|
|
||||||
use Mage\Runtime\Exception\RuntimeException;
|
|
||||||
use Mage\Runtime\Runtime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Strategy for Deployment with Rsync
|
|
||||||
*
|
|
||||||
* @author Andrés Montañez <andresmontanez@gmail.com>
|
|
||||||
*/
|
|
||||||
class RsyncStrategy implements StrategyInterface
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var Runtime
|
|
||||||
*/
|
|
||||||
protected $runtime;
|
|
||||||
|
|
||||||
public function getName()
|
|
||||||
{
|
|
||||||
return 'Rsync';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setRuntime(Runtime $runtime)
|
|
||||||
{
|
|
||||||
$this->runtime = $runtime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getPreDeployTasks()
|
|
||||||
{
|
|
||||||
$this->checkStage(Runtime::PRE_DEPLOY);
|
|
||||||
$tasks = $this->runtime->getTasks();
|
|
||||||
|
|
||||||
if ($this->runtime->getBranch() && !$this->runtime->inRollback() && !in_array('git/change-branch', $tasks)) {
|
|
||||||
array_unshift($tasks, 'git/change-branch');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $tasks;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getOnDeployTasks()
|
|
||||||
{
|
|
||||||
$this->checkStage(Runtime::ON_DEPLOY);
|
|
||||||
$tasks = $this->runtime->getTasks();
|
|
||||||
|
|
||||||
if (!$this->runtime->inRollback() && !in_array('deploy/rsync', $tasks)) {
|
|
||||||
array_unshift($tasks, 'deploy/rsync');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $tasks;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getOnReleaseTasks()
|
|
||||||
{
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getPostReleaseTasks()
|
|
||||||
{
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getPostDeployTasks()
|
|
||||||
{
|
|
||||||
$this->checkStage(Runtime::POST_DEPLOY);
|
|
||||||
$tasks = $this->runtime->getTasks();
|
|
||||||
|
|
||||||
if ($this->runtime->getBranch() && !$this->runtime->inRollback() && !in_array('git/change-branch', $tasks)) {
|
|
||||||
array_push($tasks, 'git/change-branch');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $tasks;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check the runtime stage is correct
|
|
||||||
*
|
|
||||||
* @param $stage
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
private function checkStage($stage)
|
|
||||||
{
|
|
||||||
if ($this->runtime->getStage() !== $stage) {
|
|
||||||
throw new RuntimeException(sprintf('Invalid stage, got "%s" but expected "%"', $this->runtime->getStage(), $stage));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* This file is part of the Magallanes package.
|
|
||||||
*
|
|
||||||
* (c) Andrés Montañez <andres@andresmontanez.com>
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Mage\Deploy\Strategy;
|
|
||||||
|
|
||||||
use Mage\Runtime\Runtime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interface for Deploy Strategies
|
|
||||||
*
|
|
||||||
* @author Andrés Montañez <andresmontanez@gmail.com>
|
|
||||||
*/
|
|
||||||
interface StrategyInterface
|
|
||||||
{
|
|
||||||
public function getName();
|
|
||||||
|
|
||||||
public function setRuntime(Runtime $runtime);
|
|
||||||
|
|
||||||
public function getPreDeployTasks();
|
|
||||||
|
|
||||||
public function getOnDeployTasks();
|
|
||||||
|
|
||||||
public function getOnReleaseTasks();
|
|
||||||
|
|
||||||
public function getPostReleaseTasks();
|
|
||||||
|
|
||||||
public function getPostDeployTasks();
|
|
||||||
}
|
|
22
src/Mage.php
22
src/Mage.php
@ -1,22 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* This file is part of the Magallanes package.
|
|
||||||
*
|
|
||||||
* (c) Andrés Montañez <andres@andresmontanez.com>
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Mage;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mallaganes base class
|
|
||||||
*
|
|
||||||
* @author Andrés Montañez <andresmontanez@gmail.com>
|
|
||||||
*/
|
|
||||||
class Mage
|
|
||||||
{
|
|
||||||
const VERSION = '4.0.0';
|
|
||||||
const CODENAME = 'Discovery One';
|
|
||||||
}
|
|
@ -1,143 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* This file is part of the Magallanes package.
|
|
||||||
*
|
|
||||||
* (c) Andrés Montañez <andres@andresmontanez.com>
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Mage;
|
|
||||||
|
|
||||||
use Mage\Command\AbstractCommand;
|
|
||||||
use Mage\Runtime\Runtime;
|
|
||||||
use Symfony\Component\Finder\Finder;
|
|
||||||
use Symfony\Component\Finder\SplFileInfo;
|
|
||||||
use Monolog\Logger;
|
|
||||||
use Monolog\Handler\StreamHandler;
|
|
||||||
use Symfony\Component\EventDispatcher\EventDispatcher;
|
|
||||||
use Symfony\Component\Console\Event\ConsoleErrorEvent;
|
|
||||||
use Symfony\Component\Console\ConsoleEvents;
|
|
||||||
use Symfony\Component\Console\Application;
|
|
||||||
use Symfony\Component\Yaml\Parser;
|
|
||||||
use Symfony\Component\Yaml\Exception\ParseException;
|
|
||||||
use ReflectionClass;
|
|
||||||
use Mage\Runtime\Exception\RuntimeException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Console Application for launching the Mage command in a standalone instance
|
|
||||||
*
|
|
||||||
* @author Andrés Montañez <andresmontanez@gmail.com>
|
|
||||||
*/
|
|
||||||
class MageApplication extends Application
|
|
||||||
{
|
|
||||||
protected $runtime;
|
|
||||||
protected $file;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $file The YAML file from which to read the configuration
|
|
||||||
*/
|
|
||||||
public function __construct($file)
|
|
||||||
{
|
|
||||||
parent::__construct('Magallanes', Mage::VERSION);
|
|
||||||
|
|
||||||
$this->file = $file;
|
|
||||||
$dispatcher = new EventDispatcher();
|
|
||||||
$this->setDispatcher($dispatcher);
|
|
||||||
|
|
||||||
$dispatcher->addListener(ConsoleEvents::ERROR, function (ConsoleErrorEvent $event) {
|
|
||||||
$output = $event->getOutput();
|
|
||||||
$command = $event->getCommand();
|
|
||||||
$output->writeln(sprintf('Oops, exception thrown while running command <info>%s</info>', $command->getName()));
|
|
||||||
$exitCode = $event->getExitCode();
|
|
||||||
$event->setError(new \LogicException('Caught exception', $exitCode, $event->getError()));
|
|
||||||
});
|
|
||||||
|
|
||||||
$this->runtime = $this->instantiateRuntime();
|
|
||||||
$this->loadBuiltInCommands();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Configure the Magallanes Application
|
|
||||||
*
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public function configure()
|
|
||||||
{
|
|
||||||
if (!file_exists($this->file) || !is_readable($this->file)) {
|
|
||||||
throw new RuntimeException(sprintf('The file "%s" does not exists or is not readable.', $this->file));
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$parser = new Parser();
|
|
||||||
$config = $parser->parse(file_get_contents($this->file));
|
|
||||||
} catch (ParseException $exception) {
|
|
||||||
throw new RuntimeException(sprintf('Error parsing the file "%s".', $this->file));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (array_key_exists('magephp', $config) && is_array($config['magephp'])) {
|
|
||||||
$logger = null;
|
|
||||||
if (array_key_exists('log_dir', $config['magephp']) && file_exists($config['magephp']['log_dir']) && is_dir($config['magephp']['log_dir'])) {
|
|
||||||
$logfile = sprintf('%s/%s.log', $config['magephp']['log_dir'], date('Ymd_His'));
|
|
||||||
$config['magephp']['log_file'] = $logfile;
|
|
||||||
|
|
||||||
$logger = new Logger('magephp');
|
|
||||||
$logger->pushHandler(new StreamHandler($logfile));
|
|
||||||
|
|
||||||
} elseif (array_key_exists('log_dir', $config['magephp']) && !is_dir($config['magephp']['log_dir'])) {
|
|
||||||
throw new RuntimeException(sprintf('The configured log_dir "%s" does not exists or is not a directory.', $config['magephp']['log_dir']));
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->runtime->setConfiguration($config['magephp']);
|
|
||||||
$this->runtime->setLogger($logger);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new RuntimeException(sprintf('The file "%s" does not have a valid Magallanes configuration.', $this->file));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads the BuiltIn Commands
|
|
||||||
*/
|
|
||||||
protected function loadBuiltInCommands()
|
|
||||||
{
|
|
||||||
$finder = new Finder();
|
|
||||||
$finder->files()->in(__DIR__ . '/Command/BuiltIn')->name('*Command.php');
|
|
||||||
|
|
||||||
/** @var SplFileInfo $file */
|
|
||||||
foreach ($finder as $file) {
|
|
||||||
$class = substr('\\Mage\\Command\\BuiltIn\\' . str_replace('/', '\\', $file->getRelativePathname()), 0, -4);
|
|
||||||
if (class_exists($class)) {
|
|
||||||
$reflex = new ReflectionClass($class);
|
|
||||||
if ($reflex->isInstantiable()) {
|
|
||||||
$command = new $class();
|
|
||||||
if ($command instanceof AbstractCommand) {
|
|
||||||
$command->setRuntime($this->runtime);
|
|
||||||
$this->add($command);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the Runtime instance to use
|
|
||||||
*
|
|
||||||
* @return Runtime
|
|
||||||
*/
|
|
||||||
protected function instantiateRuntime()
|
|
||||||
{
|
|
||||||
return new Runtime();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the Runtime instance
|
|
||||||
*
|
|
||||||
* @return Runtime
|
|
||||||
*/
|
|
||||||
public function getRuntime()
|
|
||||||
{
|
|
||||||
return $this->runtime;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* This file is part of the Magallanes package.
|
|
||||||
*
|
|
||||||
* (c) Andrés Montañez <andres@andresmontanez.com>
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Mage\Runtime\Exception;
|
|
||||||
|
|
||||||
use Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An Error occurred while running
|
|
||||||
*
|
|
||||||
* @author Andrés Montañez <andresmontanez@gmail.com>
|
|
||||||
*/
|
|
||||||
class RuntimeException extends Exception
|
|
||||||
{
|
|
||||||
}
|
|
@ -1,550 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* This file is part of the Magallanes package.
|
|
||||||
*
|
|
||||||
* (c) Andrés Montañez <andres@andresmontanez.com>
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Mage\Runtime;
|
|
||||||
|
|
||||||
use Mage\Deploy\Strategy\ReleasesStrategy;
|
|
||||||
use Mage\Deploy\Strategy\RsyncStrategy;
|
|
||||||
use Mage\Deploy\Strategy\StrategyInterface;
|
|
||||||
use Psr\Log\LoggerInterface;
|
|
||||||
use Psr\Log\LogLevel;
|
|
||||||
use Symfony\Component\Process\Process;
|
|
||||||
use Mage\Runtime\Exception\RuntimeException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runtime is a container of all run in time configuration, stages of progress, hosts being deployed, etc.
|
|
||||||
*
|
|
||||||
* @author Andrés Montañez <andresmontanez@gmail.com>
|
|
||||||
*/
|
|
||||||
class Runtime
|
|
||||||
{
|
|
||||||
const PRE_DEPLOY = 'pre-deploy';
|
|
||||||
const ON_DEPLOY = 'on-deploy';
|
|
||||||
const POST_DEPLOY = 'post-deploy';
|
|
||||||
const ON_RELEASE = 'on-release';
|
|
||||||
const POST_RELEASE = 'post-release';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array Magallanes configuration
|
|
||||||
*/
|
|
||||||
protected $configuration = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string|null Environment being deployed
|
|
||||||
*/
|
|
||||||
protected $environment;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string Stage of Deployment
|
|
||||||
*/
|
|
||||||
protected $stage;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string|null The host being deployed to
|
|
||||||
*/
|
|
||||||
protected $workingHost = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string|null The Release ID
|
|
||||||
*/
|
|
||||||
protected $releaseId = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array Hold a bag of variables for sharing information between tasks, if needed
|
|
||||||
*/
|
|
||||||
protected $vars = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var LoggerInterface|null The logger instance
|
|
||||||
*/
|
|
||||||
protected $logger;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var bool Indicates if a Rollback operation is in progress
|
|
||||||
*/
|
|
||||||
protected $rollback = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate the Release ID
|
|
||||||
*
|
|
||||||
* @return Runtime
|
|
||||||
*/
|
|
||||||
public function generateReleaseId()
|
|
||||||
{
|
|
||||||
$this->setReleaseId(date('YmdHis'));
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the Release ID
|
|
||||||
*
|
|
||||||
* @param string $releaseId Release ID
|
|
||||||
* @return Runtime
|
|
||||||
*/
|
|
||||||
public function setReleaseId($releaseId)
|
|
||||||
{
|
|
||||||
$this->releaseId = $releaseId;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the current Release ID
|
|
||||||
*
|
|
||||||
* @return null|string Release ID
|
|
||||||
*/
|
|
||||||
public function getReleaseId()
|
|
||||||
{
|
|
||||||
return $this->releaseId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the Runtime in Rollback mode On or Off
|
|
||||||
*
|
|
||||||
* @param bool $inRollback
|
|
||||||
* @return Runtime
|
|
||||||
*/
|
|
||||||
public function setRollback($inRollback)
|
|
||||||
{
|
|
||||||
$this->rollback = $inRollback;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates if Runtime is in rollback
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function inRollback()
|
|
||||||
{
|
|
||||||
return $this->rollback;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets a value in the Vars bag
|
|
||||||
*
|
|
||||||
* @param string $key Variable name
|
|
||||||
* @param string $value Variable value
|
|
||||||
* @return Runtime
|
|
||||||
*/
|
|
||||||
public function setVar($key, $value)
|
|
||||||
{
|
|
||||||
$this->vars[$key] = $value;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve a value from the Vars bag
|
|
||||||
*
|
|
||||||
* @param string $key Variable name
|
|
||||||
* @param mixed $default Variable default value, returned if not found
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getVar($key, $default = null)
|
|
||||||
{
|
|
||||||
if (array_key_exists($key, $this->vars)) {
|
|
||||||
return $this->vars[$key];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $default;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the Logger instance
|
|
||||||
*
|
|
||||||
* @param LoggerInterface $logger Logger instance
|
|
||||||
* @return Runtime
|
|
||||||
*/
|
|
||||||
public function setLogger(LoggerInterface $logger = null)
|
|
||||||
{
|
|
||||||
$this->logger = $logger;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the Magallanes Configuration to the Runtime
|
|
||||||
*
|
|
||||||
* @param array $configuration Configuration
|
|
||||||
* @return Runtime
|
|
||||||
*/
|
|
||||||
public function setConfiguration($configuration)
|
|
||||||
{
|
|
||||||
$this->configuration = $configuration;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the Configuration
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getConfiguration()
|
|
||||||
{
|
|
||||||
return $this->configuration;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the Configuration Option for a specific section in the configuration
|
|
||||||
*
|
|
||||||
* @param string $key Section name
|
|
||||||
* @param mixed $default Default value
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function getConfigOption($key, $default = null)
|
|
||||||
{
|
|
||||||
if (array_key_exists($key, $this->configuration)) {
|
|
||||||
return $this->configuration[$key];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $default;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the Configuration Option for a specific section the current Environment
|
|
||||||
*
|
|
||||||
* @param string $key Section/Parameter name
|
|
||||||
* @param mixed $default Default value
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function getEnvOption($key, $default = null)
|
|
||||||
{
|
|
||||||
if (!array_key_exists('environments', $this->configuration) || !is_array($this->configuration['environments'])) {
|
|
||||||
return $default;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!array_key_exists($this->environment, $this->configuration['environments'])) {
|
|
||||||
return $default;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (array_key_exists($key, $this->configuration['environments'][$this->environment])) {
|
|
||||||
return $this->configuration['environments'][$this->environment][$key];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $default;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shortcut to get the the configuration option for a specific environment and merge it with
|
|
||||||
* the global one (environment specific overrides the global one if present).
|
|
||||||
*
|
|
||||||
* @param $key
|
|
||||||
* @param array $defaultEnv
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getMergedOption($key, $defaultEnv = [])
|
|
||||||
{
|
|
||||||
$userGlobalOptions = $this->getConfigOption($key, $defaultEnv);
|
|
||||||
$userEnvOptions = $this->getEnvOption($key, $defaultEnv);
|
|
||||||
|
|
||||||
return array_merge(
|
|
||||||
(is_array($userGlobalOptions) ? $userGlobalOptions : []),
|
|
||||||
(is_array($userEnvOptions) ? $userEnvOptions : [])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Overwrites an Environment Configuration Option
|
|
||||||
*
|
|
||||||
* @param string $key
|
|
||||||
* @param mixed $value
|
|
||||||
* @return Runtime
|
|
||||||
*/
|
|
||||||
public function setEnvOption($key, $value)
|
|
||||||
{
|
|
||||||
if (array_key_exists('environments', $this->configuration) && is_array($this->configuration['environments'])) {
|
|
||||||
if (array_key_exists($this->environment, $this->configuration['environments'])) {
|
|
||||||
$this->configuration['environments'][$this->environment][$key] = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the working Environment
|
|
||||||
*
|
|
||||||
* @param string $environment Environment name
|
|
||||||
* @return Runtime
|
|
||||||
* @throws RuntimeException
|
|
||||||
*/
|
|
||||||
public function setEnvironment($environment)
|
|
||||||
{
|
|
||||||
if (array_key_exists('environments', $this->configuration) && array_key_exists($environment, $this->configuration['environments'])) {
|
|
||||||
$this->environment = $environment;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new RuntimeException(sprintf('The environment "%s" does not exists.', $environment), 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the current working Environment
|
|
||||||
*
|
|
||||||
* @return null|string
|
|
||||||
*/
|
|
||||||
public function getEnvironment()
|
|
||||||
{
|
|
||||||
return $this->environment;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the working stage
|
|
||||||
*
|
|
||||||
* @param string $stage Stage code
|
|
||||||
* @return Runtime
|
|
||||||
*/
|
|
||||||
public function setStage($stage)
|
|
||||||
{
|
|
||||||
$this->stage = $stage;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the current working Stage
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getStage()
|
|
||||||
{
|
|
||||||
return $this->stage;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the defined Tasks for the current Environment and Stage
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getTasks()
|
|
||||||
{
|
|
||||||
if (!array_key_exists('environments', $this->configuration) || !is_array($this->configuration['environments'])) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!array_key_exists($this->environment, $this->configuration['environments'])) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (array_key_exists($this->stage, $this->configuration['environments'][$this->environment])) {
|
|
||||||
if (is_array($this->configuration['environments'][$this->environment][$this->stage])) {
|
|
||||||
return $this->configuration['environments'][$this->environment][$this->stage];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the working Host
|
|
||||||
*
|
|
||||||
* @param string $host Host name
|
|
||||||
* @return Runtime
|
|
||||||
*/
|
|
||||||
public function setWorkingHost($host)
|
|
||||||
{
|
|
||||||
$this->workingHost = $host;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the working Host
|
|
||||||
*
|
|
||||||
* @return null|string
|
|
||||||
*/
|
|
||||||
public function getWorkingHost()
|
|
||||||
{
|
|
||||||
return $this->workingHost;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Logs a Message into the Logger
|
|
||||||
*
|
|
||||||
* @param string $message Log message
|
|
||||||
* @param string $level Log Level
|
|
||||||
*/
|
|
||||||
public function log($message, $level = LogLevel::DEBUG)
|
|
||||||
{
|
|
||||||
if ($this->logger instanceof LoggerInterface) {
|
|
||||||
$this->logger->log($level, $message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes a command, it will be run Locally or Remotely based on the working Stage
|
|
||||||
*
|
|
||||||
* @param string $cmd Command to execute
|
|
||||||
* @param int $timeout Seconds to wait
|
|
||||||
* @return Process
|
|
||||||
*/
|
|
||||||
public function runCommand($cmd, $timeout = 120)
|
|
||||||
{
|
|
||||||
switch ($this->getStage()) {
|
|
||||||
case self::ON_DEPLOY:
|
|
||||||
case self::ON_RELEASE:
|
|
||||||
case self::POST_RELEASE:
|
|
||||||
return $this->runRemoteCommand($cmd, true, $timeout);
|
|
||||||
default:
|
|
||||||
return $this->runLocalCommand($cmd, $timeout);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute a command locally
|
|
||||||
*
|
|
||||||
* @param string $cmd Command to execute
|
|
||||||
* @param int $timeout Seconds to wait
|
|
||||||
* @return Process
|
|
||||||
*/
|
|
||||||
public function runLocalCommand($cmd, $timeout = 120)
|
|
||||||
{
|
|
||||||
$this->log($cmd, LogLevel::INFO);
|
|
||||||
|
|
||||||
$process = Process::fromShellCommandline($cmd);
|
|
||||||
$process->setTimeout($timeout);
|
|
||||||
$process->run();
|
|
||||||
|
|
||||||
$this->log($process->getOutput(), LogLevel::DEBUG);
|
|
||||||
if (!$process->isSuccessful()) {
|
|
||||||
$this->log($process->getErrorOutput(), LogLevel::ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $process;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes a command remotely, if jail is true, it will run inside the Host Path and the Release (if available)
|
|
||||||
*
|
|
||||||
* @param string $cmd Command to execute
|
|
||||||
* @param bool $jail Jail the command
|
|
||||||
* @param int $timeout Seconds to wait
|
|
||||||
* @return Process
|
|
||||||
*/
|
|
||||||
public function runRemoteCommand($cmd, $jail, $timeout = 120)
|
|
||||||
{
|
|
||||||
$user = $this->getEnvOption('user', $this->getCurrentUser());
|
|
||||||
$sudo = $this->getEnvOption('sudo', false);
|
|
||||||
$host = $this->getHostName();
|
|
||||||
$sshConfig = $this->getSSHConfig();
|
|
||||||
|
|
||||||
$cmdDelegate = $cmd;
|
|
||||||
if ($sudo === true) {
|
|
||||||
$cmdDelegate = sprintf('sudo %s', $cmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
$hostPath = rtrim($this->getEnvOption('host_path'), '/');
|
|
||||||
if ($jail && $this->getReleaseId() !== null) {
|
|
||||||
$cmdDelegate = sprintf('cd %s/releases/%s && %s', $hostPath, $this->getReleaseId(), $cmdDelegate);
|
|
||||||
} elseif ($jail) {
|
|
||||||
$cmdDelegate = sprintf('cd %s && %s', $hostPath, $cmdDelegate);
|
|
||||||
}
|
|
||||||
|
|
||||||
$cmdRemote = str_replace('"', '\"', $cmdDelegate);
|
|
||||||
$cmdLocal = sprintf('ssh -p %d %s %s@%s "%s"', $sshConfig['port'], $sshConfig['flags'], $user, $host, $cmdRemote);
|
|
||||||
|
|
||||||
return $this->runLocalCommand($cmdLocal, $timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the SSH configuration based on the environment
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getSSHConfig()
|
|
||||||
{
|
|
||||||
$sshConfig = $this->getEnvOption('ssh', ['port' => 22, 'flags' => '-q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no']);
|
|
||||||
|
|
||||||
if ($this->getHostPort() !== null) {
|
|
||||||
$sshConfig['port'] = $this->getHostPort();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!array_key_exists('port', $sshConfig)) {
|
|
||||||
$sshConfig['port'] = '22';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!array_key_exists('flags', $sshConfig)) {
|
|
||||||
$sshConfig['flags'] = '-q -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $sshConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the current Host Port or default ssh port
|
|
||||||
*
|
|
||||||
* @return integer
|
|
||||||
*/
|
|
||||||
public function getHostPort()
|
|
||||||
{
|
|
||||||
$info = explode(':', $this->getWorkingHost());
|
|
||||||
return isset($info[1]) ? $info[1] : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the current Host Name
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getHostName()
|
|
||||||
{
|
|
||||||
if (strpos($this->getWorkingHost(), ':') === false) {
|
|
||||||
return $this->getWorkingHost();
|
|
||||||
}
|
|
||||||
|
|
||||||
$info = explode(':', $this->getWorkingHost());
|
|
||||||
return $info[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a Temporal File name
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getTempFile()
|
|
||||||
{
|
|
||||||
return tempnam(sys_get_temp_dir(), 'mage');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the current user
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getCurrentUser()
|
|
||||||
{
|
|
||||||
$userData = posix_getpwuid(posix_geteuid());
|
|
||||||
return $userData['name'];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shortcut for getting Branch information
|
|
||||||
*
|
|
||||||
* @return boolean|string
|
|
||||||
*/
|
|
||||||
public function getBranch()
|
|
||||||
{
|
|
||||||
return $this->getEnvOption('branch', false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Guesses the Deploy Strategy to use
|
|
||||||
*
|
|
||||||
* @return StrategyInterface
|
|
||||||
*/
|
|
||||||
public function guessStrategy()
|
|
||||||
{
|
|
||||||
$strategy = new RsyncStrategy();
|
|
||||||
|
|
||||||
if ($this->getEnvOption('releases', false)) {
|
|
||||||
$strategy = new ReleasesStrategy();
|
|
||||||
}
|
|
||||||
|
|
||||||
$strategy->setRuntime($this);
|
|
||||||
return $strategy;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,89 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* This file is part of the Magallanes package.
|
|
||||||
*
|
|
||||||
* (c) Andrés Montañez <andres@andresmontanez.com>
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Mage\Task;
|
|
||||||
|
|
||||||
use Mage\Runtime\Runtime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abstract base class for Magallanes Tasks
|
|
||||||
*
|
|
||||||
* @author Andrés Montañez <andresmontanez@gmail.com>
|
|
||||||
*/
|
|
||||||
abstract class AbstractTask
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var array Task custom options
|
|
||||||
*/
|
|
||||||
protected $options = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Runtime
|
|
||||||
*/
|
|
||||||
protected $runtime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the Name/Code of the Task
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
abstract public function getName();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a short Description of the Task
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
abstract public function getDescription();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes the Command
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
abstract public function execute();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set additional Options for the Task
|
|
||||||
*
|
|
||||||
* @param array $options Options
|
|
||||||
* @return AbstractTask
|
|
||||||
*/
|
|
||||||
public function setOptions($options = [])
|
|
||||||
{
|
|
||||||
if (!is_array($options)) {
|
|
||||||
$options = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->options = array_merge($this->getDefaults(), $options);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the Runtime instance
|
|
||||||
*
|
|
||||||
* @param Runtime $runtime
|
|
||||||
* @return AbstractTask
|
|
||||||
*/
|
|
||||||
public function setRuntime(Runtime $runtime)
|
|
||||||
{
|
|
||||||
$this->runtime = $runtime;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return Default options
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getDefaults()
|
|
||||||
{
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* This file is part of the Magallanes package.
|
|
||||||
*
|
|
||||||
* (c) Andrés Montañez <andres@andresmontanez.com>
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Mage\Task\BuiltIn\Composer;
|
|
||||||
|
|
||||||
use Mage\Task\AbstractTask;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abstract Composer Task
|
|
||||||
*
|
|
||||||
* @author Andrés Montañez <andresmontanez@gmail.com>
|
|
||||||
*/
|
|
||||||
abstract class AbstractComposerTask extends AbstractTask
|
|
||||||
{
|
|
||||||
protected function getOptions()
|
|
||||||
{
|
|
||||||
$options = array_merge(
|
|
||||||
['path' => 'composer'],
|
|
||||||
$this->getComposerOptions(),
|
|
||||||
$this->runtime->getMergedOption('composer'),
|
|
||||||
$this->options
|
|
||||||
);
|
|
||||||
|
|
||||||
return $options;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getComposerOptions()
|
|
||||||
{
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,47 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* This file is part of the Magallanes package.
|
|
||||||
*
|
|
||||||
* (c) Andrés Montañez <andres@andresmontanez.com>
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Mage\Task\BuiltIn\Composer;
|
|
||||||
|
|
||||||
use Symfony\Component\Process\Process;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Composer Task - Generate Autoload
|
|
||||||
*
|
|
||||||
* @author Andrés Montañez <andresmontanez@gmail.com>
|
|
||||||
*/
|
|
||||||
class DumpAutoloadTask extends AbstractComposerTask
|
|
||||||
{
|
|
||||||
public function getName()
|
|
||||||
{
|
|
||||||
return 'composer/dump-autoload';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDescription()
|
|
||||||
{
|
|
||||||
return '[Composer] Dump Autoload';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function execute()
|
|
||||||
{
|
|
||||||
$options = $this->getOptions();
|
|
||||||
$cmd = sprintf('%s dump-autoload %s', $options['path'], $options['flags']);
|
|
||||||
|
|
||||||
/** @var Process $process */
|
|
||||||
$process = $this->runtime->runCommand(trim($cmd));
|
|
||||||
|
|
||||||
return $process->isSuccessful();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getComposerOptions()
|
|
||||||
{
|
|
||||||
return ['flags' => '--optimize'];
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,47 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* This file is part of the Magallanes package.
|
|
||||||
*
|
|
||||||
* (c) Andrés Montañez <andres@andresmontanez.com>
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Mage\Task\BuiltIn\Composer;
|
|
||||||
|
|
||||||
use Symfony\Component\Process\Process;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Composer Task - Install Vendors
|
|
||||||
*
|
|
||||||
* @author Andrés Montañez <andresmontanez@gmail.com>
|
|
||||||
*/
|
|
||||||
class InstallTask extends AbstractComposerTask
|
|
||||||
{
|
|
||||||
public function getName()
|
|
||||||
{
|
|
||||||
return 'composer/install';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDescription()
|
|
||||||
{
|
|
||||||
return '[Composer] Install';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function execute()
|
|
||||||
{
|
|
||||||
$options = $this->getOptions();
|
|
||||||
$cmd = sprintf('%s install %s', $options['path'], $options['flags']);
|
|
||||||
|
|
||||||
/** @var Process $process */
|
|
||||||
$process = $this->runtime->runCommand(trim($cmd), $options['timeout']);
|
|
||||||
|
|
||||||
return $process->isSuccessful();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getComposerOptions()
|
|
||||||
{
|
|
||||||
return ['flags' => '--optimize-autoloader', 'timeout' => 120];
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,86 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* This file is part of the Magallanes package.
|
|
||||||
*
|
|
||||||
* (c) Andrés Montañez <andres@andresmontanez.com>
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Mage\Task\BuiltIn\Composer;
|
|
||||||
|
|
||||||
use Mage\Task\Exception\SkipException;
|
|
||||||
use Symfony\Component\Process\Process;
|
|
||||||
use DateTime;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Composer Task - Self update
|
|
||||||
*
|
|
||||||
* @author Yanick Witschi <https://github.com/Toflar>
|
|
||||||
*/
|
|
||||||
class SelfUpdateTask extends AbstractComposerTask
|
|
||||||
{
|
|
||||||
public function getName()
|
|
||||||
{
|
|
||||||
return 'composer/self-update';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDescription()
|
|
||||||
{
|
|
||||||
return '[Composer] Self Update';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function execute()
|
|
||||||
{
|
|
||||||
$options = $this->getOptions();
|
|
||||||
$cmdVersion = sprintf('%s --version', $options['path']);
|
|
||||||
/** @var Process $process */
|
|
||||||
$process = $this->runtime->runCommand(trim($cmdVersion));
|
|
||||||
if (!$process->isSuccessful()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$buildDate = $this->getBuildDate($process->getOutput());
|
|
||||||
if (!$buildDate instanceof DateTime) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$compareDate = $this->getCompareDate();
|
|
||||||
if ($buildDate >= $compareDate) {
|
|
||||||
throw new SkipException();
|
|
||||||
}
|
|
||||||
|
|
||||||
$cmdUpdate = sprintf('%s self-update', $options['path']);
|
|
||||||
/** @var Process $process */
|
|
||||||
$process = $this->runtime->runCommand(trim($cmdUpdate));
|
|
||||||
|
|
||||||
return $process->isSuccessful();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getBuildDate($output)
|
|
||||||
{
|
|
||||||
$buildDate = null;
|
|
||||||
$output = explode(PHP_EOL, $output);
|
|
||||||
foreach ($output as $row) {
|
|
||||||
if (strpos($row, 'Composer version ') === 0) {
|
|
||||||
$buildDate = DateTime::createFromFormat('Y-m-d H:i:s', substr(trim($row), -19));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $buildDate;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getCompareDate()
|
|
||||||
{
|
|
||||||
$options = $this->getOptions();
|
|
||||||
$compareDate = new DateTime();
|
|
||||||
$compareDate->modify(sprintf('now -%d days', $options['days']));
|
|
||||||
return $compareDate;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getComposerOptions()
|
|
||||||
{
|
|
||||||
return ['days' => 60];
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,67 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* This file is part of the Magallanes package.
|
|
||||||
*
|
|
||||||
* (c) Andrés Montañez <andres@andresmontanez.com>
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Mage\Task\BuiltIn\Deploy\Release;
|
|
||||||
|
|
||||||
use Symfony\Component\Process\Process;
|
|
||||||
use Mage\Task\AbstractTask;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Release Task - Cleanup old releases
|
|
||||||
*
|
|
||||||
* @author Andrés Montañez <andresmontanez@gmail.com>
|
|
||||||
*/
|
|
||||||
class CleanupTask extends AbstractTask
|
|
||||||
{
|
|
||||||
public function getName()
|
|
||||||
{
|
|
||||||
return 'deploy/release/cleanup';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDescription()
|
|
||||||
{
|
|
||||||
return '[Release] Cleaning up old Releases';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function execute()
|
|
||||||
{
|
|
||||||
$hostPath = rtrim($this->runtime->getEnvOption('host_path'), '/');
|
|
||||||
$currentReleaseId = $this->runtime->getReleaseId();
|
|
||||||
$maxReleases = $this->runtime->getEnvOption('releases');
|
|
||||||
|
|
||||||
$cmdListReleases = sprintf('ls -1 %s/releases', $hostPath);
|
|
||||||
|
|
||||||
/** @var Process $process */
|
|
||||||
$process = $this->runtime->runRemoteCommand($cmdListReleases, false);
|
|
||||||
if ($process->isSuccessful()) {
|
|
||||||
$releases = $process->getOutput();
|
|
||||||
$releases = explode(PHP_EOL, trim($releases));
|
|
||||||
|
|
||||||
if (count($releases) > $maxReleases) {
|
|
||||||
sort($releases);
|
|
||||||
$releasesToDelete = array_slice($releases, 0, count($releases) - $maxReleases);
|
|
||||||
foreach ($releasesToDelete as $releaseId) {
|
|
||||||
if ($releaseId != $currentReleaseId) {
|
|
||||||
$cmdDeleteRelease = sprintf('rm -rf %s/releases/%s', $hostPath, $releaseId);
|
|
||||||
/** @var Process $process */
|
|
||||||
$process = $this->runtime->runRemoteCommand($cmdDeleteRelease, false);
|
|
||||||
if (!$process->isSuccessful()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,43 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* This file is part of the Magallanes package.
|
|
||||||
*
|
|
||||||
* (c) Andrés Montañez <andres@andresmontanez.com>
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Mage\Task\BuiltIn\Deploy\Release;
|
|
||||||
|
|
||||||
use Symfony\Component\Process\Process;
|
|
||||||
use Mage\Task\AbstractTask;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Release Task - Create the Release Directory
|
|
||||||
*
|
|
||||||
* @author Andrés Montañez <andresmontanez@gmail.com>
|
|
||||||
*/
|
|
||||||
class PrepareTask extends AbstractTask
|
|
||||||
{
|
|
||||||
public function getName()
|
|
||||||
{
|
|
||||||
return 'deploy/release/prepare';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDescription()
|
|
||||||
{
|
|
||||||
return '[Release] Preparing Release';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function execute()
|
|
||||||
{
|
|
||||||
$hostPath = rtrim($this->runtime->getEnvOption('host_path'), '/');
|
|
||||||
|
|
||||||
$cmdMakeDir = sprintf('mkdir -p %s/releases/%s', $hostPath, $this->runtime->getReleaseId());
|
|
||||||
|
|
||||||
/** @var Process $process */
|
|
||||||
$process = $this->runtime->runRemoteCommand($cmdMakeDir, false);
|
|
||||||
return $process->isSuccessful();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,50 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* This file is part of the Magallanes package.
|
|
||||||
*
|
|
||||||
* (c) Andrés Montañez <andres@andresmontanez.com>
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Mage\Task\BuiltIn\Deploy;
|
|
||||||
|
|
||||||
use Mage\Task\Exception\ErrorException;
|
|
||||||
use Mage\Task\ExecuteOnRollbackInterface;
|
|
||||||
use Symfony\Component\Process\Process;
|
|
||||||
use Mage\Task\AbstractTask;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Release Task - Create the Symlink
|
|
||||||
*
|
|
||||||
* @author Andrés Montañez <andresmontanez@gmail.com>
|
|
||||||
*/
|
|
||||||
class ReleaseTask extends AbstractTask implements ExecuteOnRollbackInterface
|
|
||||||
{
|
|
||||||
public function getName()
|
|
||||||
{
|
|
||||||
return 'deploy/release';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDescription()
|
|
||||||
{
|
|
||||||
return '[Release] Creating Symlink';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function execute()
|
|
||||||
{
|
|
||||||
if (!$this->runtime->getEnvOption('releases', false)) {
|
|
||||||
throw new ErrorException('This task is only available with releases enabled', 40);
|
|
||||||
}
|
|
||||||
|
|
||||||
$hostPath = rtrim($this->runtime->getEnvOption('host_path'), '/');
|
|
||||||
$releaseId = $this->runtime->getReleaseId();
|
|
||||||
|
|
||||||
$cmdLinkRelease = sprintf('cd %s && ln -snf releases/%s current', $hostPath, $releaseId);
|
|
||||||
|
|
||||||
/** @var Process $process */
|
|
||||||
$process = $this->runtime->runRemoteCommand($cmdLinkRelease, false, null);
|
|
||||||
return $process->isSuccessful();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,67 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* This file is part of the Magallanes package.
|
|
||||||
*
|
|
||||||
* (c) Andrés Montañez <andres@andresmontanez.com>
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Mage\Task\BuiltIn\Deploy;
|
|
||||||
|
|
||||||
use Mage\Task\Exception\ErrorException;
|
|
||||||
use Symfony\Component\Process\Process;
|
|
||||||
use Mage\Task\AbstractTask;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Rsync Task - Copy files with Rsync
|
|
||||||
*
|
|
||||||
* @author Andrés Montañez <andresmontanez@gmail.com>
|
|
||||||
*/
|
|
||||||
class RsyncTask extends AbstractTask
|
|
||||||
{
|
|
||||||
public function getName()
|
|
||||||
{
|
|
||||||
return 'deploy/rsync';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDescription()
|
|
||||||
{
|
|
||||||
return '[Deploy] Copying files with Rsync';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function execute()
|
|
||||||
{
|
|
||||||
$flags = $this->runtime->getEnvOption('rsync', '-avz');
|
|
||||||
$sshConfig = $this->runtime->getSSHConfig();
|
|
||||||
$user = $this->runtime->getEnvOption('user', $this->runtime->getCurrentUser());
|
|
||||||
$host = $this->runtime->getHostName();
|
|
||||||
$hostPath = rtrim($this->runtime->getEnvOption('host_path'), '/');
|
|
||||||
$targetDir = rtrim($hostPath, '/');
|
|
||||||
|
|
||||||
if ($this->runtime->getEnvOption('releases', false)) {
|
|
||||||
throw new ErrorException('Can\'t be used with Releases, use "deploy/tar/copy"');
|
|
||||||
}
|
|
||||||
|
|
||||||
$excludes = $this->getExcludes();
|
|
||||||
$from = $this->runtime->getEnvOption('from', './');
|
|
||||||
$cmdRsync = sprintf('rsync -e "ssh -p %d %s" %s %s %s %s@%s:%s', $sshConfig['port'], $sshConfig['flags'], $flags, $excludes, $from, $user, $host, $targetDir);
|
|
||||||
|
|
||||||
/** @var Process $process */
|
|
||||||
$process = $this->runtime->runLocalCommand($cmdRsync, null);
|
|
||||||
return $process->isSuccessful();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getExcludes()
|
|
||||||
{
|
|
||||||
$excludes = $this->runtime->getMergedOption('exclude', []);
|
|
||||||
$excludes = array_merge(['.git'], array_filter($excludes));
|
|
||||||
|
|
||||||
foreach ($excludes as &$exclude) {
|
|
||||||
$exclude = '--exclude=' . $exclude;
|
|
||||||
}
|
|
||||||
|
|
||||||
return implode(' ', $excludes);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,48 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* This file is part of the Magallanes package.
|
|
||||||
*
|
|
||||||
* (c) Andrés Montañez <andres@andresmontanez.com>
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Mage\Task\BuiltIn\Deploy\Tar;
|
|
||||||
|
|
||||||
use Mage\Task\Exception\ErrorException;
|
|
||||||
use Symfony\Component\Process\Process;
|
|
||||||
use Mage\Task\AbstractTask;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tar Task - Delete temporal Tar
|
|
||||||
*
|
|
||||||
* @author Andrés Montañez <andresmontanez@gmail.com>
|
|
||||||
*/
|
|
||||||
class CleanupTask extends AbstractTask
|
|
||||||
{
|
|
||||||
public function getName()
|
|
||||||
{
|
|
||||||
return 'deploy/tar/cleanup';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDescription()
|
|
||||||
{
|
|
||||||
return '[Deploy] Cleanup Tar file';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function execute()
|
|
||||||
{
|
|
||||||
if (!$this->runtime->getEnvOption('releases', false)) {
|
|
||||||
throw new ErrorException('This task is only available with releases enabled', 40);
|
|
||||||
}
|
|
||||||
|
|
||||||
$tarLocal = $this->runtime->getVar('tar_local');
|
|
||||||
|
|
||||||
$cmdDeleteTar = sprintf('rm %s', $tarLocal);
|
|
||||||
|
|
||||||
/** @var Process $process */
|
|
||||||
$process = $this->runtime->runLocalCommand($cmdDeleteTar);
|
|
||||||
return $process->isSuccessful();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,69 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* This file is part of the Magallanes package.
|
|
||||||
*
|
|
||||||
* (c) Andrés Montañez <andres@andresmontanez.com>
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Mage\Task\BuiltIn\Deploy\Tar;
|
|
||||||
|
|
||||||
use Mage\Task\Exception\ErrorException;
|
|
||||||
use Symfony\Component\Process\Process;
|
|
||||||
use Mage\Task\AbstractTask;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tar Task - Copy Tar
|
|
||||||
*
|
|
||||||
* @author Andrés Montañez <andresmontanez@gmail.com>
|
|
||||||
*/
|
|
||||||
class CopyTask extends AbstractTask
|
|
||||||
{
|
|
||||||
public function getName()
|
|
||||||
{
|
|
||||||
return 'deploy/tar/copy';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDescription()
|
|
||||||
{
|
|
||||||
return '[Deploy] Copying files with Tar';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function execute()
|
|
||||||
{
|
|
||||||
if (!$this->runtime->getEnvOption('releases', false)) {
|
|
||||||
throw new ErrorException('This task is only available with releases enabled', 40);
|
|
||||||
}
|
|
||||||
|
|
||||||
$user = $this->runtime->getEnvOption('user', $this->runtime->getCurrentUser());
|
|
||||||
$host = $this->runtime->getHostName();
|
|
||||||
$sshConfig = $sshConfig = $this->runtime->getSSHConfig();
|
|
||||||
$hostPath = rtrim($this->runtime->getEnvOption('host_path'), '/');
|
|
||||||
$currentReleaseId = $this->runtime->getReleaseId();
|
|
||||||
|
|
||||||
$tarPath = $this->runtime->getEnvOption('tar_extract_path', 'tar');
|
|
||||||
$flags = $this->runtime->getEnvOption('tar_extract', 'xfzop');
|
|
||||||
$targetDir = sprintf('%s/releases/%s', $hostPath, $currentReleaseId);
|
|
||||||
|
|
||||||
$tarLocal = $this->runtime->getVar('tar_local');
|
|
||||||
$tarRemote = basename($tarLocal);
|
|
||||||
|
|
||||||
$cmdCopy = sprintf('scp -P %d %s %s %s@%s:%s/%s', $sshConfig['port'], $sshConfig['flags'], $tarLocal, $user, $host, $targetDir, $tarRemote);
|
|
||||||
|
|
||||||
/** @var Process $process */
|
|
||||||
$process = $this->runtime->runLocalCommand($cmdCopy, 300);
|
|
||||||
if ($process->isSuccessful()) {
|
|
||||||
$cmdUnTar = sprintf('cd %s && %s %s %s', $targetDir, $tarPath, $flags, $tarRemote);
|
|
||||||
$process = $this->runtime->runRemoteCommand($cmdUnTar, false, 600);
|
|
||||||
if ($process->isSuccessful()) {
|
|
||||||
$cmdDelete = sprintf('rm %s/%s', $targetDir, $tarRemote);
|
|
||||||
$process = $this->runtime->runRemoteCommand($cmdDelete, false);
|
|
||||||
return $process->isSuccessful();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,65 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* This file is part of the Magallanes package.
|
|
||||||
*
|
|
||||||
* (c) Andrés Montañez <andres@andresmontanez.com>
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Mage\Task\BuiltIn\Deploy\Tar;
|
|
||||||
|
|
||||||
use Mage\Task\Exception\ErrorException;
|
|
||||||
use Symfony\Component\Process\Process;
|
|
||||||
use Mage\Task\AbstractTask;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tar Task - Create temporal Tar
|
|
||||||
*
|
|
||||||
* @author Andrés Montañez <andresmontanez@gmail.com>
|
|
||||||
*/
|
|
||||||
class PrepareTask extends AbstractTask
|
|
||||||
{
|
|
||||||
public function getName()
|
|
||||||
{
|
|
||||||
return 'deploy/tar/prepare';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDescription()
|
|
||||||
{
|
|
||||||
return '[Deploy] Preparing Tar file';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function execute()
|
|
||||||
{
|
|
||||||
if (!$this->runtime->getEnvOption('releases', false)) {
|
|
||||||
throw new ErrorException('This task is only available with releases enabled', 40);
|
|
||||||
}
|
|
||||||
|
|
||||||
$tarLocal = $this->runtime->getTempFile();
|
|
||||||
$this->runtime->setVar('tar_local', $tarLocal);
|
|
||||||
|
|
||||||
$excludes = $this->getExcludes();
|
|
||||||
$tarPath = $this->runtime->getEnvOption('tar_create_path', 'tar');
|
|
||||||
$flags = $this->runtime->getEnvOption('tar_create', 'cfzp');
|
|
||||||
$from = $this->runtime->getEnvOption('from', './');
|
|
||||||
$cmdTar = sprintf('%s %s %s %s %s', $tarPath, $flags, $tarLocal, $excludes, $from);
|
|
||||||
|
|
||||||
/** @var Process $process */
|
|
||||||
$process = $this->runtime->runLocalCommand($cmdTar, 300);
|
|
||||||
return $process->isSuccessful();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getExcludes()
|
|
||||||
{
|
|
||||||
$excludes = $this->runtime->getMergedOption('exclude', []);
|
|
||||||
$excludes = array_merge(['.git'], array_filter($excludes));
|
|
||||||
|
|
||||||
foreach ($excludes as &$exclude) {
|
|
||||||
$exclude = '--exclude="' . $exclude . '"';
|
|
||||||
}
|
|
||||||
|
|
||||||
return implode(' ', $excludes);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,76 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* This file is part of the Magallanes package.
|
|
||||||
*
|
|
||||||
* (c) Andrés Montañez <andres@andresmontanez.com>
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Mage\Task\BuiltIn;
|
|
||||||
|
|
||||||
use Mage\Task\Exception\ErrorException;
|
|
||||||
use Mage\Task\AbstractTask;
|
|
||||||
use Symfony\Component\Process\Process;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exec task. Allows you to execute arbitrary commands.
|
|
||||||
*
|
|
||||||
* @author Yanick Witschi <https://github.com/Toflar>
|
|
||||||
*/
|
|
||||||
class ExecTask extends AbstractTask
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getName()
|
|
||||||
{
|
|
||||||
return 'exec';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getDescription()
|
|
||||||
{
|
|
||||||
$options = $this->getOptions();
|
|
||||||
|
|
||||||
if ($options['desc']) {
|
|
||||||
return '[Exec] ' . $options['desc'];
|
|
||||||
}
|
|
||||||
|
|
||||||
return '[Exec] Custom command';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return bool
|
|
||||||
*
|
|
||||||
* @throws ErrorException
|
|
||||||
*/
|
|
||||||
public function execute()
|
|
||||||
{
|
|
||||||
$options = $this->getOptions();
|
|
||||||
|
|
||||||
if (!$options['cmd']) {
|
|
||||||
throw new ErrorException('Parameter "cmd" is not defined');
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @var Process $process */
|
|
||||||
$process = $this->runtime->runCommand($options['cmd'], $options['timeout']);
|
|
||||||
return $process->isSuccessful();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
protected function getOptions()
|
|
||||||
{
|
|
||||||
$options = array_merge(
|
|
||||||
['cmd' => '', 'desc' => '', 'timeout' => 120],
|
|
||||||
$this->options
|
|
||||||
);
|
|
||||||
|
|
||||||
return $options;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,79 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* This file is part of the Magallanes package.
|
|
||||||
*
|
|
||||||
* (c) Andrés Montañez <andres@andresmontanez.com>
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Mage\Task\BuiltIn\FS;
|
|
||||||
|
|
||||||
use Mage\Task\Exception\ErrorException;
|
|
||||||
use Mage\Task\AbstractTask;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* File System Task - Abstract Base class for File Operations
|
|
||||||
*
|
|
||||||
* @author Andrés Montañez <andresmontanez@gmail.com>
|
|
||||||
*/
|
|
||||||
abstract class AbstractFileTask extends AbstractTask
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Returns the Task options
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
* @throws ErrorException
|
|
||||||
*/
|
|
||||||
protected function getOptions()
|
|
||||||
{
|
|
||||||
$mandatory = $this->getParameters();
|
|
||||||
$defaults = array_keys($this->getDefaults());
|
|
||||||
$missing = array_diff($mandatory, $defaults);
|
|
||||||
|
|
||||||
foreach ($missing as $parameter) {
|
|
||||||
if (!array_key_exists($parameter, $this->options)) {
|
|
||||||
throw new ErrorException(sprintf('Parameter "%s" is not defined', $parameter));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->options;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the mandatory parameters
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
abstract protected function getParameters();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a file with the placeholders replaced
|
|
||||||
*
|
|
||||||
* @param string $file
|
|
||||||
* @return string
|
|
||||||
* @throws ErrorException
|
|
||||||
*/
|
|
||||||
protected function getFile($file)
|
|
||||||
{
|
|
||||||
$mapping = [
|
|
||||||
'%environment%' => $this->runtime->getEnvironment(),
|
|
||||||
];
|
|
||||||
|
|
||||||
if ($this->runtime->getHostName() !== null) {
|
|
||||||
$mapping['%host%'] = $this->runtime->getHostName();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->runtime->getReleaseId() !== null) {
|
|
||||||
$mapping['%release%'] = $this->runtime->getReleaseId();
|
|
||||||
}
|
|
||||||
|
|
||||||
$options = $this->getOptions();
|
|
||||||
return str_replace(
|
|
||||||
array_keys($mapping),
|
|
||||||
array_values($mapping),
|
|
||||||
$options[$file]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,60 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
* This file is part of the Magallanes package.
|
|
||||||
*
|
|
||||||
* (c) Andrés Montañez <andres@andresmontanez.com>
|
|
||||||
*
|
|
||||||
* For the full copyright and license information, please view the LICENSE
|
|
||||||
* file that was distributed with this source code.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Mage\Task\BuiltIn\FS;
|
|
||||||
|
|
||||||
use Symfony\Component\Process\Process;
|
|
||||||
use Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* File System Task - Copy a File
|
|
||||||
*
|
|
||||||
* @author Marian Bäuerle
|
|
||||||
*/
|
|
||||||
class ChangeModeTask extends AbstractFileTask
|
|
||||||
{
|
|
||||||
public function getName()
|
|
||||||
{
|
|
||||||
return 'fs/chmod';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDescription()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
return sprintf('[FS] Change mode of "%s" to "%s"', $this->getFile('file'), $this->options['mode']);
|
|
||||||
} catch (Exception $exception) {
|
|
||||||
return '[FS] Chmod [missing parameters]';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function execute()
|
|
||||||
{
|
|
||||||
$file = $this->getFile('file');
|
|
||||||
$mode = $this->options['mode'];
|
|
||||||
$flags = $this->options['flags'];
|
|
||||||
|
|
||||||
$cmd = sprintf('chmod %s %s "%s"', $flags, $mode, $file);
|
|
||||||
|
|
||||||
/** @var Process $process */
|
|
||||||
$process = $this->runtime->runCommand($cmd);
|
|
||||||
|
|
||||||
return $process->isSuccessful();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getParameters()
|
|
||||||
{
|
|
||||||
return ['file', 'mode', 'flags'];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getDefaults()
|
|
||||||
{
|
|
||||||
return ['flags' => null];
|
|
||||||
}
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user