From 9a7743e8d3b7017425ac412f03b54b1b39ef8b3d Mon Sep 17 00:00:00 2001 From: Dan Cryer Date: Mon, 14 Jul 2014 14:01:29 +0100 Subject: [PATCH] Initial work on adding a Services layer to PHPCI, for better testability. Starting with Projects --- PHPCI/Controller/ProjectController.php | 47 +++++---- PHPCI/Service/ProjectService.php | 105 +++++++++++++++++++++ Tests/PHPCI/Service/MockProjectStore.php | 15 +++ Tests/PHPCI/Service/ProjectServiceTest.php | 101 ++++++++++++++++++++ phpunit.xml | 3 + 5 files changed, 245 insertions(+), 26 deletions(-) create mode 100644 PHPCI/Service/ProjectService.php create mode 100644 Tests/PHPCI/Service/MockProjectStore.php create mode 100644 Tests/PHPCI/Service/ProjectServiceTest.php diff --git a/PHPCI/Controller/ProjectController.php b/PHPCI/Controller/ProjectController.php index 38986c59..1906fb8c 100644 --- a/PHPCI/Controller/ProjectController.php +++ b/PHPCI/Controller/ProjectController.php @@ -20,6 +20,7 @@ use PHPCI\Helper\Github; use PHPCI\Helper\SshKey; use PHPCI\Model\Build; use PHPCI\Model\Project; +use PHPCI\Service\ProjectService; /** * Project Controller - Allows users to create, edit and view projects. @@ -39,10 +40,16 @@ class ProjectController extends \PHPCI\Controller */ protected $projectStore; + /** + * @var \PHPCI\Service\ProjectService + */ + protected $projectService; + public function init() { $this->buildStore = Store\Factory::getStore('Build'); $this->projectStore = Store\Factory::getStore('Project'); + $this->projectService = new ProjectService($this->projectStore); } /** @@ -179,35 +186,23 @@ class ProjectController extends \PHPCI\Controller return $view->render(); } else { - return $this->addProject($form); + $title = $this->getParam('title', 'New Project'); + $reference = $this->getParam('reference', null); + $type = $this->getParam('type', null); + + $options = array( + 'ssh_private_key' => $this->getParam('key', null), + 'ssh_public_key' => $this->getParam('pubkey', null), + 'build_config' => $this->getParam('build_config', null), + 'allow_public_status' => $this->getParam('allow_public_status', 0), + ); + + $project = $this->projectService->createProject($title, $reference, $type, $options); + header('Location: '.PHPCI_URL.'project/view/' . $project->getId()); + die; } } - protected function addProject(Form $form) - { - $values = $form->getValues(); - - $matches = array(); - if ($values['type'] == "gitlab" && preg_match('`^(.*)@(.*):(.*)/(.*)\.git`', $values['reference'], $matches)) { - $info = array(); - $info['user'] = $matches[1]; - $info['domain'] = $matches[2]; - $values['access_information'] = serialize($info); - $values['reference'] = $matches[3]."/".$matches[4]; - } - - $values['ssh_private_key'] = $values['key']; - $values['ssh_public_key'] = $values['pubkey']; - - $project = new Project(); - $project->setValues($values); - - $project = $this->projectStore->save($project); - - header('Location: '.PHPCI_URL.'project/view/' . $project->getId()); - die; - } - /** * Edit a project. Handles both the form and processing. */ diff --git a/PHPCI/Service/ProjectService.php b/PHPCI/Service/ProjectService.php new file mode 100644 index 00000000..ee2ef7b2 --- /dev/null +++ b/PHPCI/Service/ProjectService.php @@ -0,0 +1,105 @@ +projectStore = $projectStore; + } + + /** + * Create a new project model and use the project store to save it. + * @param string $title + * @param string $type + * @param string $reference + * @param array $options + * @return \PHPCI\Model\Project + */ + public function createProject($title, $type, $reference, $options = array()) + { + // Create base project and use updateProject() to set its properties: + $project = new Project(); + return $this->updateProject($project, $title, $type, $reference, $options); + } + + /** + * Update the properties of a given project. + * @param Project $project + * @param string $title + * @param string $type + * @param string $reference + * @param array $options + * @return \PHPCI\Model\Project + */ + public function updateProject(Project $project, $title, $type, $reference, $options = array()) + { + // Set basic properties: + $project->setTitle($title); + $project->setType($type); + $project->setReference($reference); + + // Handle extra project options: + if (array_key_exists('ssh_private_key', $options)) { + $project->setSshPrivateKey($options['ssh_private_key']); + } + + if (array_key_exists('ssh_public_key', $options)) { + $project->setSshPublicKey($options['ssh_public_key']); + } + + if (array_key_exists('build_config', $options)) { + $project->setBuildConfig($options['build_config']); + } + + if (array_key_exists('allow_public_status', $options)) { + $project->setAllowPublicStatus((int)$options['allow_public_status']); + } + + // Allow certain project types to set access information: + $this->processAccessInformation($project); + + // Save and return the project: + return $this->projectStore->save($project); + } + + /** + * In circumstances where it is necessary, populate access information based on other project properties. + * @see ProjectService::createProject() + * @param Project $project + */ + protected function processAccessInformation(Project &$project) + { + $matches = array(); + $reference = $project->getReference(); + + if ($project->getType() == 'gitlab' && preg_match('`^(.*)@(.*):(.*)/(.*)\.git`', $reference, $matches)) { + $info = array(); + $info['user'] = $matches[1]; + $info['domain'] = $matches[2]; + + /** @todo At a later date, we need to find a way to replace this serialized data with JSON */ + $project->setAccessInformation(serialize($info)); + $project->setReference($matches[3] . '/' . $matches[4]); + } + } +} diff --git a/Tests/PHPCI/Service/MockProjectStore.php b/Tests/PHPCI/Service/MockProjectStore.php new file mode 100644 index 00000000..a19f5e69 --- /dev/null +++ b/Tests/PHPCI/Service/MockProjectStore.php @@ -0,0 +1,15 @@ +setId(1); + return $project; + } +} diff --git a/Tests/PHPCI/Service/ProjectServiceTest.php b/Tests/PHPCI/Service/ProjectServiceTest.php new file mode 100644 index 00000000..b0ff30d6 --- /dev/null +++ b/Tests/PHPCI/Service/ProjectServiceTest.php @@ -0,0 +1,101 @@ + + */ +class ProjectServiceTest extends \PHPUnit_Framework_TestCase +{ + + /** + * @var ProjectService $testedService + */ + protected $testedService; + + /** + * @var \ $mockProjectStore + */ + protected $mockProjectStore; + + public function setUp() + { + $this->mockProjectStore = new MockProjectStore(); + $this->testedService = new ProjectService($this->mockProjectStore); + } + + /** + * @covers PHPUnit::execute + */ + public function testExecute_CreateBasicProject() + { + $returnValue = $this->testedService->createProject('Test Project', 'github', 'block8/phpci'); + + $this->assertEquals('Test Project', $returnValue->getTitle()); + $this->assertEquals('github', $returnValue->getType()); + $this->assertEquals('block8/phpci', $returnValue->getReference()); + } + + /** + * @covers PHPUnit::execute + */ + public function testExecute_CreateProjectWithOptions() + { + $options = array( + 'ssh_private_key' => 'private', + 'ssh_public_key' => 'public', + 'allow_public_status' => 1, + 'build_config' => 'config', + ); + + $returnValue = $this->testedService->createProject('Test Project', 'github', 'block8/phpci', $options); + + $this->assertEquals('private', $returnValue->getSshPrivateKey()); + $this->assertEquals('public', $returnValue->getSshPublicKey()); + $this->assertEquals('config', $returnValue->getBuildConfig()); + $this->assertEquals(1, $returnValue->getAllowPublicStatus()); + } + + /** + * @link https://github.com/Block8/PHPCI/issues/484 + * @covers PHPUnit::execute + */ + public function testExecute_CreateGitlabProjectWithoutPort() + { + $reference = 'git@gitlab.block8.net:block8/phpci.git'; + $returnValue = $this->testedService->createProject('Gitlab', 'gitlab', $reference); + + $this->assertEquals('git', $returnValue->getAccessInformation('user')); + $this->assertEquals('gitlab.block8.net', $returnValue->getAccessInformation('domain')); + $this->assertEquals('block8/phpci', $returnValue->getReference()); + } + + /** + * @covers PHPUnit::execute + */ + public function testExecute_UpdateExistingProject() + { + $project = new Project(); + $project->setTitle('Before Title'); + $project->setReference('Before Reference'); + $project->setType('github'); + + $returnValue = $this->testedService->updateProject($project, 'After Title', 'bitbucket', 'After Reference'); + + $this->assertEquals('After Title', $returnValue->getTitle()); + $this->assertEquals('After Reference', $returnValue->getReference()); + $this->assertEquals('bitbucket', $returnValue->getType()); + } +} diff --git a/phpunit.xml b/phpunit.xml index 15bd43aa..0e1d6810 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -20,5 +20,8 @@ ./Tests/PHPCI/Plugin + + ./Tests/PHPCI/Service +