Skip to content
This repository has been archived by the owner on Apr 16, 2024. It is now read-only.

Commit

Permalink
Merge pull request #87 from niels-nijens/maintenance-task-strategies
Browse files Browse the repository at this point in the history
Implemented strategies in MaintenanceTask as described in #69
  • Loading branch information
niels-nijens committed Dec 16, 2015
2 parents 704aa65 + b660a6a commit 1a1bb41
Show file tree
Hide file tree
Showing 4 changed files with 343 additions and 1 deletion.
24 changes: 23 additions & 1 deletion src/Task/MaintenanceTask.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
use Accompli\EventDispatcher\Event\PrepareDeployReleaseEvent;
use Accompli\EventDispatcher\Event\WorkspaceEvent;
use Accompli\EventDispatcher\EventDispatcherInterface;
use Accompli\Utility\VersionCategoryComparator;
use InvalidArgumentException;
use Psr\Log\LogLevel;
use RuntimeException;

Expand All @@ -17,6 +19,13 @@
*/
class MaintenanceTask extends AbstractConnectedTask
{
/**
* The maintenance page strategy.
*
* @var string
*/
private $strategy;

/**
* The local path to the directory containing the maintenance page.
*
Expand All @@ -41,9 +50,18 @@ public static function getSubscribedEvents()

/**
* Constructs a new MaintenanceTask.
*
* @param string $strategy
*
* @throws InvalidArgumentException
*/
public function __construct()
public function __construct($strategy = VersionCategoryComparator::MATCH_MAJOR_DIFFERENCE)
{
if (in_array($strategy, array(VersionCategoryComparator::MATCH_MAJOR_DIFFERENCE, VersionCategoryComparator::MATCH_MINOR_DIFFERENCE, VersionCategoryComparator::MATCH_ALWAYS)) === false) {
throw new InvalidArgumentException(sprintf('The strategy type "%s" is invalid.', $strategy));
}

$this->strategy = $strategy;
$this->localMaintenanceDirectory = realpath(__DIR__.'/../Resources/maintenance');
}

Expand Down Expand Up @@ -109,6 +127,10 @@ public function onPrepareWorkspaceUploadMaintenancePage(WorkspaceEvent $event, $
*/
public function onPrepareDeployReleaseLinkMaintenancePageToStage(PrepareDeployReleaseEvent $event, $eventName, EventDispatcherInterface $eventDispatcher)
{
if (VersionCategoryComparator::matchesStrategy($this->strategy, $event->getRelease(), $event->getCurrentRelease()) === false) {
return;
}

$host = $event->getWorkspace()->getHost();
$connection = $this->ensureConnection($host);

Expand Down
113 changes: 113 additions & 0 deletions src/Utility/VersionCategoryComparator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
<?php

namespace Accompli\Utility;

use Accompli\Deployment\Release;
use InvalidArgumentException;

/**
* VersionCategoryComparator.
*
* @author Niels Nijens <nijens.niels@gmail.com>
*/
class VersionCategoryComparator
{
/**
* The major version category.
*
* @var string
*/
const MAJOR = 'major';

/**
* The minor version category.
*
* @var string
*/
const MINOR = 'minor';

/**
* The patch version category.
*
* @var string
*/
const PATCH = 'patch';

/**
* Match only when the difference between two versions is a major version.
*
* @var string
*/
const MATCH_MAJOR_DIFFERENCE = 'major_difference';

/**
* Match when the difference between two versions is a major or minor version.
*
* @var string
*/
const MATCH_MINOR_DIFFERENCE = 'minor_difference';

/**
* Match always.
*
* @var string
*/
const MATCH_ALWAYS = 'always';

/**
* Returns the highest version category difference between two Release instances.
*
* @param Release $release1
* @param Release|null $release2
*
* @return string|null
*/
public static function getDifference(Release $release1, Release $release2 = null)
{
if ($release2 === null) {
return self::MAJOR;
}

$version1 = explode('.', $release1->getVersion());
$version2 = explode('.', $release2->getVersion());
if (isset($version1[0]) === false || isset($version2[0]) === false || $version1[0] != $version2[0]) {
return self::MAJOR;
} elseif (isset($version1[1]) === false || isset($version2[1]) === false || $version1[1] != $version2[1]) {
return self::MINOR;
} elseif (isset($version1[2]) === false || isset($version2[2]) === false || $version1[2] != $version2[2]) {
return self::PATCH;
}
}

/**
* Returns true when the version category difference matches the supplied match strategy.
*
* @param string $strategy
* @param Release $release1
* @param Release $release2
*
* @return bool
*
* @throws InvalidArgumentException
*/
public static function matchesStrategy($strategy, Release $release1, Release $release2 = null)
{
if (in_array($strategy, array(self::MATCH_MAJOR_DIFFERENCE, self::MATCH_MINOR_DIFFERENCE, self::MATCH_ALWAYS)) === false) {
throw new InvalidArgumentException(sprintf('The match strategy "%s" is invalid.', $strategy));
}

if ($strategy === self::MATCH_ALWAYS) {
return true;
}

$match = false;
$versionCategoryDifference = self::getDifference($release1, $release2);
if ($strategy === self::MATCH_MAJOR_DIFFERENCE && $versionCategoryDifference === self::MAJOR) {
$match = true;
} elseif ($strategy === self::MATCH_MINOR_DIFFERENCE && in_array($versionCategoryDifference, array(self::MAJOR, self::MINOR))) {
$match = true;
}

return $match;
}
}
83 changes: 83 additions & 0 deletions tests/Task/MaintenanceTaskTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

use Accompli\AccompliEvents;
use Accompli\Task\MaintenanceTask;
use Accompli\Utility\VersionCategoryComparator;
use PHPUnit_Framework_TestCase;
use RuntimeException;

/**
* MaintenanceTaskTest.
Expand All @@ -30,9 +32,21 @@ public function testConstruct()
{
$task = new MaintenanceTask();

$this->assertAttributeSame(VersionCategoryComparator::MATCH_MAJOR_DIFFERENCE, 'strategy', $task);
$this->assertAttributeSame(realpath(__DIR__.'/../../src/Resources/maintenance'), 'localMaintenanceDirectory', $task);
}

/**
* Tests if constructing a new MaintenanceTask with an invalid strategy throws an InvalidArgumentException.
*
* @expectedException InvalidArgumentException
* @expectedExceptionMessage The strategy type "invalid" is invalid.
*/
public function testConstructThrowsInvalidArgumentException()
{
new MaintenanceTask('invalid');
}

/**
* Tests if MaintenanceTask::onPrepareWorkspaceUploadMaintenancePage calls the connection adapter to create and upload the maintenance page in the workspace.
*/
Expand Down Expand Up @@ -175,12 +189,19 @@ public function testOnPrepareDeployReleaseLinkMaintenancePageToStage()
->method('getHost')
->willReturn($hostMock);

$releaseMock = $this->getMockBuilder('Accompli\Deployment\Release')
->disableOriginalConstructor()
->getMock();

$eventMock = $this->getMockBuilder('Accompli\EventDispatcher\Event\PrepareDeployReleaseEvent')
->disableOriginalConstructor()
->getMock();
$eventMock->expects($this->once())
->method('getWorkspace')
->willReturn($workspaceMock);
$eventMock->expects($this->once())
->method('getRelease')
->willReturn($releaseMock);

$task = new MaintenanceTask();
$task->onPrepareDeployReleaseLinkMaintenancePageToStage($eventMock, AccompliEvents::PREPARE_DEPLOY_RELEASE, $eventDispatcherMock);
Expand Down Expand Up @@ -214,12 +235,67 @@ public function testOnPrepareDeployReleaseLinkMaintenancePageToStageWhenStageLin
->method('getHost')
->willReturn($hostMock);

$releaseMock = $this->getMockBuilder('Accompli\Deployment\Release')
->disableOriginalConstructor()
->getMock();

$eventMock = $this->getMockBuilder('Accompli\EventDispatcher\Event\PrepareDeployReleaseEvent')
->disableOriginalConstructor()
->getMock();
$eventMock->expects($this->once())
->method('getWorkspace')
->willReturn($workspaceMock);
$eventMock->expects($this->once())
->method('getRelease')
->willReturn($releaseMock);

$task = new MaintenanceTask();
$task->onPrepareDeployReleaseLinkMaintenancePageToStage($eventMock, AccompliEvents::PREPARE_DEPLOY_RELEASE, $eventDispatcherMock);
}

/**
* Tests if MaintenanceTask::onPrepareDeployReleaseLinkMaintenancePageToStage calls the connection adapter to unlink an existing stage link and link the stage to the maintenance directory.
*/
public function testOnPrepareDeployReleaseLinkMaintenancePageToStageDoesNotExecuteWhenVersionCategoryDifferenceDoesNotMatchStrategy()
{
$eventDispatcherMock = $this->getMockBuilder('Accompli\EventDispatcher\EventDispatcherInterface')->getMock();
$eventDispatcherMock->expects($this->never())->method('dispatch');

$connectionAdapterMock = $this->getMockBuilder('Accompli\Deployment\Connection\ConnectionAdapterInterface')->getMock();
$connectionAdapterMock->expects($this->never())->method('isConnected');
$connectionAdapterMock->expects($this->never())->method('isLink');
$connectionAdapterMock->expects($this->never())->method('link');
$connectionAdapterMock->expects($this->never())->method('delete');

$hostMock = $this->getMockBuilder('Accompli\Deployment\Host')
->disableOriginalConstructor()
->getMock();
$hostMock->expects($this->never())->method('hasConnection');
$hostMock->expects($this->never())->method('getConnection');
$hostMock->expects($this->never())->method('getStage');

$workspaceMock = $this->getMockBuilder('Accompli\Deployment\Workspace')
->disableOriginalConstructor()
->getMock();
$workspaceMock->expects($this->never())->method('getHost');

$releaseMock = $this->getMockBuilder('Accompli\Deployment\Release')
->disableOriginalConstructor()
->getMock();
$releaseMock->expects($this->exactly(2))
->method('getVersion')
->willReturn('0.1.0');

$eventMock = $this->getMockBuilder('Accompli\EventDispatcher\Event\PrepareDeployReleaseEvent')
->disableOriginalConstructor()
->getMock();
$eventMock->expects($this->never())->method('getWorkspace');
$eventMock->expects($this->once())
->method('getRelease')
->willReturn($releaseMock);
$eventMock->expects($this->once())
->method('getCurrentRelease')
->willReturn($releaseMock);

$task = new MaintenanceTask();
$task->onPrepareDeployReleaseLinkMaintenancePageToStage($eventMock, AccompliEvents::PREPARE_DEPLOY_RELEASE, $eventDispatcherMock);
Expand Down Expand Up @@ -256,12 +332,19 @@ public function testOnPrepareDeployReleaseLinkMaintenancePageToStageFailure()
->method('getHost')
->willReturn($hostMock);

$releaseMock = $this->getMockBuilder('Accompli\Deployment\Release')
->disableOriginalConstructor()
->getMock();

$eventMock = $this->getMockBuilder('Accompli\EventDispatcher\Event\PrepareDeployReleaseEvent')
->disableOriginalConstructor()
->getMock();
$eventMock->expects($this->once())
->method('getWorkspace')
->willReturn($workspaceMock);
$eventMock->expects($this->once())
->method('getRelease')
->willReturn($releaseMock);

$task = new MaintenanceTask();
$task->onPrepareDeployReleaseLinkMaintenancePageToStage($eventMock, AccompliEvents::PREPARE_DEPLOY_RELEASE, $eventDispatcherMock);
Expand Down
Loading

0 comments on commit 1a1bb41

Please sign in to comment.