├── data ├── db │ └── .gitkeep ├── packages │ └── .gitkeep └── logs │ └── .gitkeep ├── .dockerignore ├── module └── DeployAgent │ ├── view │ ├── agent │ │ └── index.phtml │ ├── layout │ │ └── layout.phtml │ └── error │ │ ├── index.phtml │ │ └── 404.phtml │ ├── src │ ├── Task │ │ ├── Runner │ │ │ ├── Exception.php │ │ │ ├── TaskRunnerInterface.php │ │ │ ├── Command.php │ │ │ └── TaskRunnerManager.php │ │ ├── TaskManagerFactory.php │ │ └── TaskManager.php │ ├── Source │ │ └── SourceInterface.php │ ├── Exception │ │ └── FileSystemException.php │ ├── Resource │ │ ├── ResourceInterface.php │ │ ├── Archive │ │ │ ├── Extractor │ │ │ │ ├── ExtractorInterface.php │ │ │ │ ├── ValidationResult.php │ │ │ │ ├── TarGzExtractor.php │ │ │ │ └── ZipExtractor.php │ │ │ └── Archive.php │ │ ├── AbstractResource.php │ │ ├── Http │ │ │ └── Http.php │ │ └── FileSystem │ │ │ └── Directory.php │ ├── Iterator │ │ ├── IteratorAwareInterface.php │ │ ├── WrappedFilterInterface.php │ │ ├── RecursiveDirectoryAggregate.php │ │ ├── CallbackFilter.php │ │ └── FilterIteratorAwareTrait.php │ ├── EntityRepositoryProviderInterface.php │ ├── Destination │ │ └── DestinationInterface.php │ ├── EntityManagerAwareInterface.php │ ├── Controller │ │ ├── IndexController.php │ │ ├── HookController.php │ │ └── ApplicationController.php │ ├── Transport │ │ ├── TransportInterface.php │ │ └── Transport.php │ ├── Workspace │ │ └── Workspace.php │ ├── Provider │ │ ├── ProviderInterface.php │ │ ├── AbstractProvider.php │ │ └── Continuousphp.php │ ├── Application │ │ ├── ApplicationInterface.php │ │ ├── ApplicationManager.php │ │ └── Application.php │ ├── Log │ │ └── Writer │ │ │ ├── ConsoleFactory.php │ │ │ └── Console.php │ ├── Event │ │ ├── EventBroadcasterTrait.php │ │ └── DeployEvent.php │ ├── EntityRepositoryProviderTrait.php │ ├── EntityManagerInitializer.php │ └── Agent │ │ └── Agent.php │ ├── Module.php │ └── config │ └── module.config.php ├── config ├── autoload │ ├── .gitignore │ ├── global.php │ ├── db.global.php │ ├── db.test.php.dist │ ├── local.php.dist │ └── agent.global.php └── application.config.php ├── agent ├── public ├── favicon.ico ├── .htaccess └── index.php ├── resources └── img │ └── continuousphp-setup.png ├── behat.yml ├── infra └── docker │ ├── entrypoint.sh │ ├── vhost.conf │ ├── docker-compose.yml │ ├── .htaccess │ └── Dockerfile ├── phpcs.xml ├── scripts └── post-create-project ├── continuous.yml ├── .gitignore ├── features ├── create-continuousphp-application.feature ├── list-continuousphp-application.feature ├── deploy-continuousphp-application.feature └── bootstrap │ ├── CliContext.php │ └── DeployAgentContext.php ├── composer.json ├── Vagrantfile ├── README.md └── LICENSE /data/db/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | -------------------------------------------------------------------------------- /data/packages/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /data/logs/.gitkeep: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /module/DeployAgent/view/agent/index.phtml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /config/autoload/.gitignore: -------------------------------------------------------------------------------- 1 | local.php 2 | *.local.php 3 | -------------------------------------------------------------------------------- /agent: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | 2 | 3 | Continuous Deploy Agent Coding standard 4 | 5 | module/DeployAgent/src 6 | -------------------------------------------------------------------------------- /infra/docker/vhost.conf: -------------------------------------------------------------------------------- 1 | 2 | DocumentRoot /var/app/public 3 | 4 | DirectoryIndex index.php 5 | AllowOverride All 6 | Require all granted 7 | 8 | 9 | -------------------------------------------------------------------------------- /scripts/post-create-project: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | 5 | [ 6 | 'connection' => 7 | [ 8 | 'orm_default' => 9 | [ 10 | 'driverClass' => 'Doctrine\DBAL\Driver\PDOSqlite\Driver', 11 | 'params' => 12 | [ 13 | 'path'=> __DIR__ . '/../../data/db/agent.db', 14 | ] 15 | ] 16 | ] 17 | ], 18 | ]; 19 | -------------------------------------------------------------------------------- /config/autoload/db.test.php.dist: -------------------------------------------------------------------------------- 1 | 5 | [ 6 | 'connection' => 7 | [ 8 | 'orm_default' => 9 | [ 10 | 'driverClass' => 'Doctrine\DBAL\Driver\PDOSqlite\Driver', 11 | 'params' => 12 | [ 13 | 'path'=> __DIR__ . '/../../data/db/test.db', 14 | ] 15 | ] 16 | ] 17 | ], 18 | ]; 19 | -------------------------------------------------------------------------------- /config/autoload/local.php.dist: -------------------------------------------------------------------------------- 1 | 17 | [ 18 | 'display_exceptions' => true, 19 | ] 20 | ]; 21 | -------------------------------------------------------------------------------- /module/DeployAgent/src/Task/Runner/Exception.php: -------------------------------------------------------------------------------- 1 | array( 9 | 'BsbFlysystem', 10 | 'DoctrineModule', 11 | 'Continuous\\DeployAgent', 12 | 'DoctrineORMModule' 13 | ), 14 | 'module_listener_options' => array( 15 | 'module_paths' => array( 16 | './module', 17 | './vendor', 18 | ), 19 | 'config_glob_paths' => array( 20 | __DIR__ . '/../config/autoload/{,*.}{global,local,test}.php', 21 | ), 22 | 'config_cache_key' => 'application.config.cache', 23 | 'config_cache_enabled' => false, 24 | 'module_map_cache_key' => 'application.module.cache', 25 | 'module_map_cache_enabled' => false, 26 | 'cache_dir' => 'data/cache/', 27 | ), 28 | ); 29 | -------------------------------------------------------------------------------- /config/autoload/agent.global.php: -------------------------------------------------------------------------------- 1 | 10 | [ 11 | 'adapters' => 12 | [ 13 | 'packages' => 14 | [ 15 | 'type' => 'local', 16 | 'options' => 17 | [ 18 | 'root' => './data/packages' 19 | ] 20 | ] 21 | ] 22 | ], 23 | 24 | 'agent' => [ 25 | 'package_retention' => 2, // package retention per application 26 | 'package_storage_path' => './data/packages', // flysystem adapter key to store package history 27 | /* hexadecimal key to crypt/decrypt sensitive data */ 28 | 'hash-key' => 'f01ee0962998007d40c7ce32bfec773028785cadfa0064a467662cb87171012c' 29 | ] 30 | ]; -------------------------------------------------------------------------------- /module/DeployAgent/src/Iterator/WrappedFilterInterface.php: -------------------------------------------------------------------------------- 1 | redirect()->toRoute('zf-apigility/ui'); 29 | } 30 | 31 | return new ViewModel(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /module/DeployAgent/view/layout/layout.phtml: -------------------------------------------------------------------------------- 1 | doctype(); ?> 2 | 3 | 4 | 5 | headTitle('Continuous Deploy Agent'); 7 | echo $this->headMeta()->appendName('viewport', 'width=device-width, initial-scale=1.0'); 8 | echo $this->headLink(array('rel' => 'icon', 'type' => '/image/vnd.microsoft.icon', 'href' => $this->basePath('/favicon.ico'))); 9 | ?> 10 | 11 | 12 |
13 | content; ?> 14 |
15 | 25 | inlineScript() ?> 26 | 27 | 28 | -------------------------------------------------------------------------------- /features/create-continuousphp-application.feature: -------------------------------------------------------------------------------- 1 | @continuousphp 2 | Feature: Create an application provided by continuousphp to automate the deployment of a specific pipeline 3 | 4 | Scenario: Create an application using the CLI 5 | Given I am in the "." folder 6 | When I run "./agent add application --provider=continuousphp --token=b52f9c7faf680988f88391b35e5e488883442036 --repository-provider=git-hub --repository=fdewinnetest/deploy-agent --pipeline=refs/heads/master --name=deploy-agent-staging --path=/tmp/test/application" 7 | Then the exit code should be "0" 8 | And I should have the application 9 | | provider | continuousphp | 10 | | token | b52f9c7faf680988f88391b35e5e488883442036 | 11 | | repositoryProvider | git-hub | 12 | | repository | fdewinnetest/deploy-agent | 13 | | pipeline | refs/heads/master | 14 | | name | deploy-agent-staging | 15 | | path | /tmp/test/application | -------------------------------------------------------------------------------- /module/DeployAgent/src/Resource/Archive/Extractor/ExtractorInterface.php: -------------------------------------------------------------------------------- 1 | iterator = $iterator; 37 | return $this; 38 | } 39 | 40 | /** 41 | * @return \ArrayIterator 42 | */ 43 | public function getIterator() 44 | { 45 | return $this->iterator ?: new \ArrayIterator; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /features/list-continuousphp-application.feature: -------------------------------------------------------------------------------- 1 | @continuousphp 2 | Feature: List all configured application 3 | 4 | Scenario: List no application using the CLI 5 | Given I am in the "." folder 6 | When I run "./agent list applications" 7 | Then the exit code should be "0" 8 | And the output should contain: 9 | """ 10 | No application found 11 | """ 12 | 13 | @filesystem 14 | Scenario: List an existing application using the CLI 15 | Given I am in the "." folder 16 | And I have the application 17 | | provider | continuousphp | 18 | | token | b52f9c7faf680988f88391b35e5e488883442036 | 19 | | repositoryProvider | git-hub | 20 | | repository | fdewinnetest/deploy-agent | 21 | | pipeline | refs/heads/master | 22 | | name | deploy-agent-staging | 23 | | path | /tmp/test/application | 24 | When I run "./agent list applications" 25 | Then the exit code should be "0" 26 | And the output should contain: 27 | """ 28 | deploy-agent-staging 29 | """ 30 | -------------------------------------------------------------------------------- /infra/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:7.0-apache 2 | 3 | # Set default system timezone 4 | RUN ln -sf /usr/share/zoneinfo/Europe/Paris /etc/localtime 5 | 6 | # Install last update and php extension 7 | RUN apt-get update && apt-get install -y --no-install-recommends \ 8 | vim \ 9 | bzip2 \ 10 | zip \ 11 | unzip \ 12 | libbz2-dev \ 13 | libmcrypt-dev \ 14 | libicu-dev \ 15 | && docker-php-ext-configure mysqli \ 16 | && docker-php-ext-install mysqli pdo_mysql bz2 mcrypt intl \ 17 | && rm -rf /var/lib/apt/lists/* 18 | 19 | # Install composer 20 | RUN curl -sS https://getcomposer.org/installer | php \ 21 | && mv composer.phar /usr/bin/composer 22 | 23 | # Enable Apache Rewrite module 24 | RUN a2enmod rewrite 25 | 26 | # Default Vhost for developement 27 | COPY infra/docker/vhost.conf /etc/apache2/sites-available/000-default.conf 28 | 29 | # Implement application 30 | WORKDIR /var/app 31 | COPY . /var/app/ 32 | 33 | # htaccess specific to docker app 34 | COPY infra/docker/.htaccess public/ 35 | 36 | # Update project 37 | RUN /usr/bin/composer install --no-dev \ 38 | && ./scripts/post-create-project \ 39 | && chown www-data:www-data -R . 40 | 41 | COPY infra/docker/entrypoint.sh / 42 | 43 | ENTRYPOINT ["/entrypoint.sh", "apache2-foreground"] 44 | -------------------------------------------------------------------------------- /module/DeployAgent/src/Provider/ProviderInterface.php: -------------------------------------------------------------------------------- 1 | command; 30 | } 31 | 32 | /** 33 | * @param mixed $command 34 | * @return Command 35 | */ 36 | public function setCommand($command) 37 | { 38 | $this->command = $command; 39 | return $this; 40 | } 41 | 42 | public function run() 43 | { 44 | passthru($this->getCommand(), $return); 45 | if ($return) { 46 | throw new Exception('The command exit with code ' . $return, Exception::BAD_EXIT_EXCEPTION); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /module/DeployAgent/src/Resource/AbstractResource.php: -------------------------------------------------------------------------------- 1 | filesystem; 39 | } 40 | 41 | /** 42 | * @param Filesystem $filesystem 43 | * @return AbstractResource 44 | */ 45 | public function setFilesystem($filesystem) 46 | { 47 | $this->filesystem = $filesystem; 48 | return $this; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /module/DeployAgent/src/Application/ApplicationInterface.php: -------------------------------------------------------------------------------- 1 | =5.5.0", 24 | "ext-pdo_sqlite": "*", 25 | "zendframework/zendframework": "2.5.2", 26 | "doctrine/doctrine-orm-module": "~0.10", 27 | "reprovinci/doctrine-encrypt": "~3.0", 28 | "bushbaby/flysystem": "~1.0", 29 | "continuousphp/sdk": "~0.3" 30 | }, 31 | "require-dev": { 32 | "phpunit/phpunit": "4.1.*", 33 | "mikey179/vfsStream": "1.3.*@dev", 34 | "squizlabs/php_codesniffer": "^2.3", 35 | "behat/behat": "^3.0" 36 | }, 37 | "autoload": { 38 | "psr-4": { 39 | "Continuous\\DeployAgent\\": "module/DeployAgent/src" 40 | }, 41 | "classmap": [ 42 | "module/DeployAgent/Module.php" 43 | ] 44 | }, 45 | "autoload-dev": { 46 | "psr-4": { 47 | "Continuous\\Features\\": "features/bootstrap/" 48 | } 49 | }, 50 | "scripts": { 51 | "post-create-project-cmd": "scripts/post-create-project" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /module/DeployAgent/src/Log/Writer/ConsoleFactory.php: -------------------------------------------------------------------------------- 1 | options = $options; 30 | } 31 | 32 | /** 33 | * Create service 34 | * 35 | * @param ServiceLocatorInterface $pluginManager 36 | * @return mixed 37 | */ 38 | public function createService(ServiceLocatorInterface $pluginManager) 39 | { 40 | $writer = new Console($this->options); 41 | 42 | $console = $pluginManager->getServiceLocator()->get('Console'); 43 | if ($console instanceof \Zend\Console\Adapter\AdapterInterface) { 44 | $writer->setConsole($console); 45 | } 46 | 47 | return $writer; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /module/DeployAgent/src/Iterator/RecursiveDirectoryAggregate.php: -------------------------------------------------------------------------------- 1 | isDir()) { 33 | throw new \InvalidArgumentException('Expecting directory'); 34 | } 35 | $this->iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator( 36 | $file->getPathname(), 37 | \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS 38 | )); 39 | } 40 | 41 | /** 42 | * @return \Iterator|\RecursiveIteratorIterator 43 | */ 44 | public function getIterator() 45 | { 46 | return $this->iterator; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /module/DeployAgent/src/Iterator/CallbackFilter.php: -------------------------------------------------------------------------------- 1 | callback = $callable; 38 | } 39 | 40 | /** 41 | * @param \Iterator $iterator 42 | * @return mixed 43 | */ 44 | public function getFilterIterator(\Iterator $iterator) 45 | { 46 | $filter = $this->iteratorClass; 47 | return new $filter($iterator, $this->callback); 48 | } 49 | 50 | /** 51 | * @return string 52 | */ 53 | public function getIteratorName() 54 | { 55 | return $this->iteratorClass; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /module/DeployAgent/src/Resource/Archive/Extractor/ValidationResult.php: -------------------------------------------------------------------------------- 1 | valid = (bool) $valid; 33 | 34 | return $this; 35 | } 36 | 37 | /** 38 | * @param string $message 39 | * 40 | * @return self 41 | */ 42 | public function setMessage($message) 43 | { 44 | $this->message = (string) $message; 45 | $this->valid = false; 46 | 47 | return $this; 48 | } 49 | 50 | /** 51 | * @return boolean 52 | */ 53 | public function isValid() 54 | { 55 | return $this->valid; 56 | } 57 | 58 | /** 59 | * @return string 60 | */ 61 | public function getMessage() 62 | { 63 | return $this->message; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | VAGRANTFILE_API_VERSION = '2' 5 | 6 | @script = <