├── .github ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .phpci.yml ├── LICENSE.md ├── PHPCI ├── Application.php ├── BuildFactory.php ├── Builder.php ├── Command │ ├── CreateAdminCommand.php │ ├── CreateBuildCommand.php │ ├── DaemonCommand.php │ ├── DaemoniseCommand.php │ ├── GenerateCommand.php │ ├── InstallCommand.php │ ├── PollCommand.php │ ├── RebuildCommand.php │ ├── RebuildQueueCommand.php │ ├── RunCommand.php │ ├── UpdateCommand.php │ └── WorkerCommand.php ├── Controller.php ├── Controller │ ├── BuildController.php │ ├── BuildStatusController.php │ ├── GroupController.php │ ├── HomeController.php │ ├── PluginController.php │ ├── ProjectController.php │ ├── SessionController.php │ ├── SettingsController.php │ ├── UserController.php │ └── WebhookController.php ├── ErrorHandler.php ├── Helper │ ├── AnsiConverter.php │ ├── BaseCommandExecutor.php │ ├── Build.php │ ├── BuildInterpolator.php │ ├── CommandExecutor.php │ ├── Diff.php │ ├── Email.php │ ├── Github.php │ ├── Lang.php │ ├── LoginIsDisabled.php │ ├── MailerFactory.php │ ├── SshKey.php │ ├── UnixCommandExecutor.php │ ├── User.php │ └── WindowsCommandExecutor.php ├── Languages │ ├── lang.da.php │ ├── lang.de.php │ ├── lang.el.php │ ├── lang.en.php │ ├── lang.es.php │ ├── lang.fr.php │ ├── lang.it.php │ ├── lang.nl.php │ ├── lang.pl.php │ ├── lang.pt-br.php │ ├── lang.ru.php │ ├── lang.uk.php │ └── lang.zh.php ├── Logging │ ├── BuildDBLogHandler.php │ ├── BuildLogger.php │ ├── Handler.php │ ├── LoggedBuildContextTidier.php │ ├── LoggerConfig.php │ └── OutputLogHandler.php ├── Migrations │ ├── 20140513143726_initial_migration.php │ ├── 20140513153133_change_build_keys_migration.php │ ├── 20140611170618_choose_branch.php │ ├── 20140730143702_fix_database_columns.php │ ├── 20150131075425_archive_project.php │ ├── 20150203105015_fix_column_types.php │ ├── 20150324174958_unique_email_and_name_user_fields.php │ ├── 20151008140800_add_project_groups.php │ ├── 20151009100610_remove_unique_name_index.php │ ├── 20151014091859_errors_table.php │ ├── 20151015124825_convert_errors.php │ ├── 20160310132732_brach_column_length.php │ ├── 20160623100223_project_table_defaults.php │ ├── 20161214164202_database_fixes.php │ └── 20171027132159_error_hash.php ├── Model.php ├── Model │ ├── Base │ │ ├── BuildBase.php │ │ ├── BuildErrorBase.php │ │ ├── BuildMetaBase.php │ │ ├── ProjectBase.php │ │ ├── ProjectGroupBase.php │ │ └── UserBase.php │ ├── Build.php │ ├── Build │ │ ├── BitbucketBuild.php │ │ ├── GithubBuild.php │ │ ├── GitlabBuild.php │ │ ├── LocalBuild.php │ │ ├── MercurialBuild.php │ │ ├── RemoteGitBuild.php │ │ └── SubversionBuild.php │ ├── BuildError.php │ ├── BuildMeta.php │ ├── Project.php │ ├── ProjectGroup.php │ └── User.php ├── Plugin.php ├── Plugin │ ├── Atoum.php │ ├── Behat.php │ ├── Campfire.php │ ├── CleanBuild.php │ ├── Codeception.php │ ├── Composer.php │ ├── CopyBuild.php │ ├── Deployer.php │ ├── Email.php │ ├── Env.php │ ├── FlowdockNotify.php │ ├── Git.php │ ├── Grunt.php │ ├── Gulp.php │ ├── HipchatNotify.php │ ├── Irc.php │ ├── Lint.php │ ├── Mysql.php │ ├── PackageBuild.php │ ├── Pdepend.php │ ├── Pgsql.php │ ├── Phar.php │ ├── Phing.php │ ├── PhpCodeSniffer.php │ ├── PhpCpd.php │ ├── PhpCsFixer.php │ ├── PhpDocblockChecker.php │ ├── PhpLoc.php │ ├── PhpMessDetector.php │ ├── PhpParallelLint.php │ ├── PhpSpec.php │ ├── PhpTalLint.php │ ├── PhpUnit.php │ ├── Shell.php │ ├── SlackNotify.php │ ├── Sqlite.php │ ├── TechnicalDebt.php │ ├── Util │ │ ├── ComposerPluginInformation.php │ │ ├── Executor.php │ │ ├── Factory.php │ │ ├── FilesPluginInformation.php │ │ ├── InstalledPluginInformation.php │ │ ├── PluginInformationCollection.php │ │ ├── TapParser.php │ │ └── TestResultParsers │ │ │ ├── Codeception.php │ │ │ └── ParserInterface.php │ ├── Wipe.php │ └── Xmpp.php ├── ProcessControl │ ├── Factory.php │ ├── PosixProcessControl.php │ ├── ProcessControlInterface.php │ ├── UnixProcessControl.php │ └── WindowsProcessControl.php ├── Service │ ├── BuildService.php │ ├── BuildStatusService.php │ ├── ProjectService.php │ └── UserService.php ├── Store.php ├── Store │ ├── Base │ │ ├── BuildErrorStoreBase.php │ │ ├── BuildMetaStoreBase.php │ │ ├── BuildStoreBase.php │ │ ├── ProjectGroupStoreBase.php │ │ ├── ProjectStoreBase.php │ │ └── UserStoreBase.php │ ├── BuildErrorStore.php │ ├── BuildMetaStore.php │ ├── BuildStore.php │ ├── ProjectGroupStore.php │ ├── ProjectStore.php │ └── UserStore.php ├── View │ ├── Build │ │ ├── errors.phtml │ │ ├── header-row.phtml │ │ └── view.phtml │ ├── BuildStatus │ │ └── view.phtml │ ├── BuildsTable.phtml │ ├── Email │ │ ├── layout.phtml │ │ ├── long.phtml │ │ └── short.phtml │ ├── Group │ │ ├── edit.phtml │ │ └── index.phtml │ ├── Home │ │ └── index.phtml │ ├── Plugin │ │ └── index.phtml │ ├── Project │ │ └── view.phtml │ ├── ProjectForm.phtml │ ├── Session.phtml │ ├── Session │ │ ├── forgotPassword.phtml │ │ ├── login.phtml │ │ └── resetPassword.phtml │ ├── Settings │ │ └── index.phtml │ ├── SummaryTable.phtml │ ├── User │ │ ├── index.phtml │ │ └── profile.phtml │ ├── UserForm.phtml │ ├── exception.phtml │ └── layout.phtml ├── Worker │ └── BuildWorker.php ├── ZeroConfigPlugin.php └── build │ └── .gitignore ├── README.md ├── Tests ├── PHPCI │ ├── Command │ │ ├── CreateAdminCommandTest.php │ │ ├── CreateBuildCommandTest.php │ │ └── InstallCommandTest.php │ ├── Controller │ │ └── WebhookControllerTest.php │ ├── Helper │ │ ├── AnsiConverterTest.php │ │ ├── BuildInterpolatorTest.php │ │ ├── CommandExecutorTest.php │ │ ├── LangTest.php │ │ └── MailerFactoryTest.php │ ├── Logging │ │ ├── BuildLoggerTest.php │ │ └── LoggerConfigTest.php │ ├── Model │ │ ├── BuildTest.php │ │ └── ProjectTest.php │ ├── Plugin │ │ ├── EmailTest.php │ │ ├── PharTest.php │ │ └── Util │ │ │ ├── ComposerPluginInformationTest.php │ │ │ ├── ExamplePluginConfig.php │ │ │ ├── ExecutorTest.php │ │ │ ├── FactoryTest.php │ │ │ ├── Fake │ │ │ ├── ExamplePluginFull.php │ │ │ ├── ExamplePluginWithNoConstructorArgs.php │ │ │ ├── ExamplePluginWithSingleOptionalArg.php │ │ │ ├── ExamplePluginWithSingleRequiredArg.php │ │ │ └── ExamplePluginWithSingleTypedRequiredArg.php │ │ │ ├── FilesPluginInformationTest.php │ │ │ └── TapParserTest.php │ ├── ProcessControl │ │ ├── PosixProcessControlTest.php │ │ ├── ProcessControlTest.php │ │ ├── UnixProcessControlTest.php │ │ └── WindowsProcessControlTest.php │ └── Service │ │ ├── BuildServiceTest.php │ │ ├── BuiltStatusServiceTest.php │ │ ├── ProjectServiceTest.php │ │ └── UserServiceTest.php ├── bootstrap.php └── temp │ └── .gitignore ├── bootstrap.php ├── changelog.md ├── composer.json ├── composer.lock ├── console ├── console.bat ├── daemon └── .gitignore ├── daemonise ├── docker-compose.yaml ├── docker ├── fpm-entrypoint.sh ├── fpm.dockerfile ├── nginx.conf ├── worker-entrypoint.sh └── worker.dockerfile ├── docs ├── Makefile └── source │ ├── add-a-virtual-host.md │ ├── adding-phpci-support-to-your-projects.md │ ├── atoum-plugin.md │ ├── autobuilding from atlassian stash.md │ ├── autobuilding from git by cron.md │ ├── autobuilding-from-bitbucket.md │ ├── autobuilding-from-git.md │ ├── autobuilding-from-github.md │ ├── autobuilding-from-gitlab.md │ ├── behat-plugin.md │ ├── branch-specific-stages.md │ ├── campfire-plugin.md │ ├── clean-build-plugin.md │ ├── codeception-plugin.md │ ├── composer-plugin.md │ ├── conf.py │ ├── configuring-phpci.md │ ├── contributing-to-phpci.md │ ├── copy-build-plugin.md │ ├── custom-plugins-setup.md │ ├── deployer.md │ ├── email-plugin.md │ ├── env-plugin.md │ ├── example-phpci.yml.md │ ├── grunt-plugin.md │ ├── hipchat-notify-plugin.md │ ├── index.md │ ├── installing-phpci.md │ ├── interpolation.md │ ├── irc-plugin.md │ ├── lint-plugin.md │ ├── logging.md │ ├── maintainers.md │ ├── mysql-plugin.md │ ├── package-build-plugin.md │ ├── pdepend-plugin.md │ ├── phar-plugin.md │ ├── phing-plugin.md │ ├── php-code-sniffer-plugin.md │ ├── php-coding-standards-fixer-plugin.md │ ├── php-copy-paste-detector-plugin.md │ ├── php-docblock-checker.md │ ├── php-loc-plugin.md │ ├── php-mess-detector-plugin.md │ ├── php-parallel-lint-plugin.md │ ├── php-spec-plugin.md │ ├── phpci-config.md │ ├── phpunit-plugin.md │ ├── postgresql-plugin.md │ ├── project-status-images-and-page.md │ ├── run-builds-using-a-daemon.md │ ├── run-builds-using-a-worker.md │ ├── run-builds-using-cron.md │ ├── shell-plugin.md │ ├── slack-notify-plugin.md │ ├── technical-debt-plugin.md │ ├── updating-phpci.md │ ├── vanilla-installation-on-os-x-10.10-yosemite-with-os-x-server-4.md │ ├── vanilla-mac-mavericks-server-installation-guide.md │ └── xmpp-notifications-plugin.md ├── loggerconfig.php.example ├── package-lock.json ├── package.json ├── phinx.php ├── phpcs.xml ├── phpmd.xml ├── phpunit.xml ├── pluginconfig.php.example ├── public ├── .htaccess.dist ├── assets │ ├── css │ │ ├── AdminLTE-custom.css │ │ └── ansi-colors.css │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ └── glyphicons-halflings-regular.woff │ ├── img │ │ ├── ajax-loader.gif │ │ ├── ajax-loader1.gif │ │ ├── blur-background04.jpg │ │ ├── blur-background08.jpg │ │ ├── blur-background09.jpg │ │ ├── bootstrap-colorpicker │ │ │ ├── alpha-horizontal.png │ │ │ ├── alpha.png │ │ │ ├── hue-horizontal.png │ │ │ ├── hue.png │ │ │ └── saturation.png │ │ ├── favicon.png │ │ ├── glyphicons-halflings-white.png │ │ ├── glyphicons-halflings.png │ │ ├── icon-build-failed.png │ │ ├── icon-build-ok.png │ │ ├── icon-build-pending.png │ │ ├── icon-build-running.png │ │ ├── icons.png │ │ ├── logo-icon.png │ │ ├── logo-icon.svg │ │ ├── logo-large.png │ │ ├── logo.png │ │ ├── sprite-skin-flat.png │ │ ├── sprite-skin-nice.png │ │ ├── user-bg.png │ │ ├── user.jpg │ │ └── user2.jpg │ └── js │ │ ├── build-plugins │ │ ├── codeception.js │ │ ├── loc.js │ │ ├── phpspec.js │ │ ├── phptallint.js │ │ ├── phpunit.js │ │ ├── summary.js │ │ └── warnings.js │ │ ├── build.js │ │ ├── class.js │ │ ├── init.js │ │ ├── jqueryui.js │ │ └── phpci.js ├── favicon.ico ├── index.php └── robots.txt └── vars.php /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Before submitting your issue, please make sure that you've checked all of the checkboxes below. 2 | 3 | - [ ] You're running the [latest release](https://github.com/Block8/PHPCI/releases/latest) version of PHPCI. 4 | - [ ] Ensure that you're running at least PHP 5.3.6, you can check this by running `php -v` 5 | - [ ] You've run `composer install --no-dev -o` from the root of your installation. 6 | - [ ] You have set up either the PHPCI [Worker](https://github.com/Block8/PHPCI/wiki/Run-Builds-Using-a-Worker), [Daemon](https://github.com/Block8/PHPCI/wiki/Run-Builds-Using-a-Daemon) or [Cron Job](https://github.com/Block8/PHPCI/wiki/Run-Builds-Using-Cron) to run builds. 7 | 8 | To help us better understand your issue, please answer the following. 9 | 10 | ### Expected behaviour 11 | 12 | *Please describe what you're expecting to see happen.* 13 | 14 | ### Actual behaviour 15 | 16 | *Please describe what you're actually seeing happen.* 17 | 18 | ### Steps to reproduce 19 | 20 | *If your issue requires any specific steps to reproduce, please outline them here.* 21 | 22 | ### Environment info 23 | Operating System: 24 | PHP Version: 25 | MySQL Version: 26 | 27 | ### Logs or other output that would be helpful 28 | (If logs are large, please upload as attachment). -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Contribution Type: bug fix | new plugin | new feature | refactor | cosmetic 2 | Link to Intent to Implement: 3 | Link to Bug: 4 | 5 | This pull request affects the following areas: 6 | 7 | * [ ] Front-End 8 | * [ ] Builder 9 | * [ ] Build Plugins 10 | 11 | **In raising this pull request, I confirm the following (please check boxes):** 12 | 13 | - [ ] I have read and understood the [contributing guidelines](/.github/CONTRIBUTING.md)? 14 | - [ ] I have checked that another pull request for this purpose does not exist. 15 | - [ ] I have considered, and confirmed that this submission will be valuable to others. 16 | - [ ] I have created or updated the relevant documentation for this change on the PHPCI Wiki. 17 | - [ ] Do the PHPCI tests pass? 18 | 19 | 20 | Detailed description of change: 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | vendor/ 3 | composer.phar 4 | config.php 5 | .DS_Store 6 | .settings/ 7 | .project 8 | .buildpath 9 | .htaccess 10 | PHPCI/config.yml 11 | cache 12 | /loggerconfig.php 13 | /pluginconfig.php 14 | PHPCI/Model/Migration.php 15 | PHPCI/Model/Base/MigrationBase.php 16 | PHPCI/Store/MigrationStore.php 17 | PHPCI/Store/Base/MigrationStoreBase.php 18 | local_vars.php 19 | Tests/PHPCI/config.yml 20 | /node_modules 21 | -------------------------------------------------------------------------------- /.phpci.yml: -------------------------------------------------------------------------------- 1 | build_settings: 2 | verbose: false 3 | ignore: 4 | - "vendor" 5 | - "Tests" 6 | - "PHPCI/Command" # PHPMD complains about un-used parameters, but they are required. 7 | - "public/install.php" # PHPCS really doesn't like PHP mixed with HTML (and so it shouldn't) 8 | - "PHPCI/Migrations" # Ignore the migrations directory, as both PHPMD and PHPCS can't cope with them. 9 | - "PHPCI/Model/Base" # These files are auto-generated, and sometimes hit PHPMD complexity thresholds. 10 | - "PHPCI/Languages" # PHPCS fails on character counts for non-Latin languages 11 | - "public/assets" # If there are any PHP files in here, we didn't write them. 12 | 13 | setup: 14 | composer: 15 | action: "install" 16 | 17 | test: 18 | php_parallel_lint: 19 | ignore: 20 | # Only ignore vendor 21 | - vendor/ 22 | php_mess_detector: 23 | allowed_warnings: 0 24 | rules: 25 | - phpmd.xml 26 | php_code_sniffer: 27 | standard: phpcs.xml 28 | allowed_warnings: 0 29 | allowed_errors: 0 30 | php_loc: 31 | php_unit: 32 | php_docblock_checker: 33 | allowed_warnings: 0 34 | 35 | broken: 36 | email: 37 | committer: true 38 | cc: ["php-ci@googlegroups.com"] 39 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013-2018, Block 8 Limited 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 10 | -------------------------------------------------------------------------------- /PHPCI/BuildFactory.php: -------------------------------------------------------------------------------- 1 | 18 | */ 19 | class BuildFactory 20 | { 21 | /** 22 | * @param $buildId 23 | * @return Build 24 | * @throws \Exception 25 | */ 26 | public static function getBuildById($buildId) 27 | { 28 | $build = Factory::getStore('Build')->getById($buildId); 29 | 30 | if (empty($build)) { 31 | throw new \Exception('Build ID ' . $buildId . ' does not exist.'); 32 | } 33 | 34 | return self::getBuild($build); 35 | } 36 | 37 | /** 38 | * Takes a generic build and returns a type-specific build model. 39 | * @param Build $build The build from which to get a more specific build type. 40 | * @return Build 41 | */ 42 | public static function getBuild(Build $build) 43 | { 44 | $project = $build->getProject(); 45 | 46 | if (!empty($project)) { 47 | switch ($project->getType()) { 48 | case 'remote': 49 | $type = 'RemoteGitBuild'; 50 | break; 51 | case 'local': 52 | $type = 'LocalBuild'; 53 | break; 54 | case 'github': 55 | $type = 'GithubBuild'; 56 | break; 57 | case 'bitbucket': 58 | $type = 'BitbucketBuild'; 59 | break; 60 | case 'gitlab': 61 | $type = 'GitlabBuild'; 62 | break; 63 | case 'hg': 64 | $type = 'MercurialBuild'; 65 | break; 66 | case 'svn': 67 | $type = 'SubversionBuild'; 68 | break; 69 | default: 70 | return $build; 71 | } 72 | 73 | $class = '\\PHPCI\\Model\\Build\\' . $type; 74 | $build = new $class($build->getDataArray()); 75 | } 76 | 77 | return $build; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /PHPCI/Command/GenerateCommand.php: -------------------------------------------------------------------------------- 1 | 21 | * @package PHPCI 22 | * @subpackage Console 23 | */ 24 | class GenerateCommand extends Command 25 | { 26 | protected function configure() 27 | { 28 | $this 29 | ->setName('phpci:generate') 30 | ->setDescription('Generate models and stores from the database.'); 31 | } 32 | 33 | /** 34 | * Generates Model and Store classes by reading database meta data. 35 | */ 36 | protected function execute(InputInterface $input, OutputInterface $output) 37 | { 38 | $gen = new CodeGenerator( 39 | Database::getConnection(), 40 | array('default' => 'PHPCI'), 41 | array('default' => PHPCI_DIR), 42 | false 43 | ); 44 | 45 | $gen->generateModels(); 46 | $gen->generateStores(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /PHPCI/Command/RebuildCommand.php: -------------------------------------------------------------------------------- 1 | 23 | * @package PHPCI 24 | * @subpackage Console 25 | */ 26 | class RebuildCommand extends Command 27 | { 28 | /** 29 | * @var Logger 30 | */ 31 | protected $logger; 32 | 33 | /** 34 | * @var OutputInterface 35 | */ 36 | protected $output; 37 | 38 | /** 39 | * @var boolean 40 | */ 41 | protected $run; 42 | 43 | /** 44 | * @var int 45 | */ 46 | protected $sleep; 47 | 48 | /** 49 | * @param \Monolog\Logger $logger 50 | * @param string $name 51 | */ 52 | public function __construct(Logger $logger, $name = null) 53 | { 54 | parent::__construct($name); 55 | $this->logger = $logger; 56 | } 57 | 58 | protected function configure() 59 | { 60 | $this 61 | ->setName('phpci:rebuild') 62 | ->setDescription('Re-runs the last run build.'); 63 | } 64 | 65 | /** 66 | * Loops through running. 67 | */ 68 | protected function execute(InputInterface $input, OutputInterface $output) 69 | { 70 | $runner = new RunCommand($this->logger); 71 | $runner->setMaxBuilds(1); 72 | $runner->setDaemon(false); 73 | 74 | /** @var \PHPCI\Store\BuildStore $store */ 75 | $store = Factory::getStore('Build'); 76 | $service = new BuildService($store); 77 | 78 | $builds = $store->getLatestBuilds(null, 1); 79 | $lastBuild = array_shift($builds); 80 | $service->createDuplicateBuild($lastBuild); 81 | 82 | $runner->run(new ArgvInput(array()), $output); 83 | } 84 | 85 | /** 86 | * Called when log entries are made in Builder / the plugins. 87 | * @see \PHPCI\Builder::log() 88 | */ 89 | public function logCallback($log) 90 | { 91 | $this->output->writeln($log); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /PHPCI/Command/RebuildQueueCommand.php: -------------------------------------------------------------------------------- 1 | 26 | * @package PHPCI 27 | * @subpackage Console 28 | */ 29 | class RebuildQueueCommand extends Command 30 | { 31 | /** 32 | * @var OutputInterface 33 | */ 34 | protected $output; 35 | 36 | /** 37 | * @var Logger 38 | */ 39 | protected $logger; 40 | 41 | /** 42 | * @param \Monolog\Logger $logger 43 | * @param string $name 44 | */ 45 | public function __construct(Logger $logger, $name = null) 46 | { 47 | parent::__construct($name); 48 | $this->logger = $logger; 49 | } 50 | 51 | protected function configure() 52 | { 53 | $this 54 | ->setName('phpci:rebuild-queue') 55 | ->setDescription('Rebuilds the PHPCI worker queue.'); 56 | } 57 | 58 | protected function execute(InputInterface $input, OutputInterface $output) 59 | { 60 | $this->output = $output; 61 | 62 | // For verbose mode we want to output all informational and above 63 | // messages to the symphony output interface. 64 | if ($input->hasOption('verbose') && $input->getOption('verbose')) { 65 | $this->logger->pushHandler( 66 | new OutputLogHandler($this->output, Logger::INFO) 67 | ); 68 | } 69 | 70 | $store = Factory::getStore('Build'); 71 | $result = $store->getByStatus(0); 72 | 73 | $this->logger->addInfo(Lang::get('found_n_builds', count($result['items']))); 74 | 75 | $buildService = new BuildService($store); 76 | 77 | while (count($result['items'])) { 78 | $build = array_shift($result['items']); 79 | $build = BuildFactory::getBuild($build); 80 | 81 | $this->logger->addInfo('Added build #' . $build->getId() . ' to queue.'); 82 | $buildService->addBuildToQueue($build); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /PHPCI/Command/UpdateCommand.php: -------------------------------------------------------------------------------- 1 | 22 | * @package PHPCI 23 | * @subpackage Console 24 | */ 25 | class UpdateCommand extends Command 26 | { 27 | /** 28 | * @var \Monolog\Logger 29 | */ 30 | protected $logger; 31 | 32 | public function __construct(Logger $logger, $name = null) 33 | { 34 | parent::__construct($name); 35 | $this->logger = $logger; 36 | } 37 | 38 | protected function configure() 39 | { 40 | $this 41 | ->setName('phpci:update') 42 | ->setDescription(Lang::get('update_phpci')); 43 | } 44 | 45 | /** 46 | * Generates Model and Store classes by reading database meta data. 47 | */ 48 | protected function execute(InputInterface $input, OutputInterface $output) 49 | { 50 | if (!$this->verifyInstalled($output)) { 51 | return; 52 | } 53 | 54 | $output->write(Lang::get('updating_phpci')); 55 | 56 | shell_exec(PHPCI_DIR . 'vendor/bin/phinx migrate -c "' . PHPCI_DIR . 'phinx.php"'); 57 | 58 | $output->writeln(''.Lang::get('ok').''); 59 | } 60 | 61 | protected function verifyInstalled(OutputInterface $output) 62 | { 63 | $config = Config::getInstance(); 64 | $phpciUrl = $config->get('phpci.url'); 65 | 66 | return !empty($phpciUrl); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /PHPCI/Controller/PluginController.php: -------------------------------------------------------------------------------- 1 | 21 | * @package PHPCI 22 | * @subpackage Web 23 | */ 24 | class PluginController extends \PHPCI\Controller 25 | { 26 | /** 27 | * List all enabled plugins, installed and recommend packages. 28 | * @return string 29 | */ 30 | public function index() 31 | { 32 | $this->requireAdmin(); 33 | 34 | $json = $this->getComposerJson(); 35 | $this->view->installedPackages = $json['require']; 36 | 37 | $pluginInfo = new PluginInformationCollection(); 38 | $pluginInfo->add(FilesPluginInformation::newFromDir( 39 | PHPCI_DIR . "PHPCI/Plugin/" 40 | )); 41 | $pluginInfo->add(ComposerPluginInformation::buildFromYaml( 42 | PHPCI_DIR . "vendor/composer/installed.json" 43 | )); 44 | 45 | $this->view->plugins = $pluginInfo->getInstalledPlugins(); 46 | 47 | $this->layout->title = Lang::get('plugins'); 48 | 49 | return $this->view->render(); 50 | } 51 | 52 | /** 53 | * Get the json-decoded contents of the composer.json file. 54 | * @return mixed 55 | */ 56 | protected function getComposerJson() 57 | { 58 | $json = file_get_contents(APPLICATION_PATH . 'composer.json'); 59 | return json_decode($json, true); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /PHPCI/ErrorHandler.php: -------------------------------------------------------------------------------- 1 | 'Warning', 24 | E_NOTICE => 'Notice', 25 | E_USER_ERROR => 'User Error', 26 | E_USER_WARNING => 'User Warning', 27 | E_USER_NOTICE => 'User Notice', 28 | E_STRICT => 'Runtime Notice', 29 | E_RECOVERABLE_ERROR => 'Catchable Fatal Error', 30 | E_DEPRECATED => 'Deprecated', 31 | E_USER_DEPRECATED => 'User Deprecated', 32 | ); 33 | 34 | /** 35 | * Registers an instance of the error handler to throw ErrorException. 36 | */ 37 | public static function register() 38 | { 39 | $handler = new static(); 40 | set_error_handler(array($handler, 'handleError')); 41 | } 42 | 43 | /** 44 | * @param integer $level 45 | * @param string $message 46 | * @param string $file 47 | * @param integer $line 48 | * 49 | * @throws \ErrorException 50 | * 51 | * @internal 52 | */ 53 | public function handleError($level, $message, $file, $line) 54 | { 55 | if (error_reporting() & $level === 0) { 56 | return; 57 | } 58 | 59 | $exceptionLevel = isset($this->levels[$level]) ? $this->levels[$level] : $level; 60 | throw new \ErrorException( 61 | sprintf('%s: %s in %s line %d', $exceptionLevel, $message, $file, $line), 62 | 0, 63 | $level, 64 | $file, 65 | $line 66 | ); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /PHPCI/Helper/AnsiConverter.php: -------------------------------------------------------------------------------- 1 | convert($text); 47 | } 48 | 49 | /** 50 | * Do not instantiate this class. 51 | */ 52 | private function __construct() 53 | { 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /PHPCI/Helper/Build.php: -------------------------------------------------------------------------------- 1 | 15 | * @package PHPCI 16 | * @subpackage Web 17 | */ 18 | class Build 19 | { 20 | /** 21 | * Returns a more human-friendly version of a plugin name. 22 | * @param $name 23 | * @return mixed 24 | */ 25 | public function formatPluginName($name) 26 | { 27 | return str_replace('Php', 'PHP', ucwords(str_replace('_', ' ', $name))); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /PHPCI/Helper/CommandExecutor.php: -------------------------------------------------------------------------------- 1 | 17 | * @package PHPCI 18 | * @subpackage Web 19 | */ 20 | class LoginIsDisabled 21 | { 22 | /** 23 | * Checks if 24 | * @param $method 25 | * @param array $params 26 | * @return mixed|null 27 | */ 28 | public function __call($method, $params = array()) 29 | { 30 | unset($method, $params); 31 | 32 | $config = Config::getInstance(); 33 | $state = (bool) $config->get('phpci.authentication_settings.state', false); 34 | 35 | return (false !== $state); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /PHPCI/Helper/SshKey.php: -------------------------------------------------------------------------------- 1 | '', 'public_key' => ''); 41 | 42 | $output = @shell_exec('ssh-keygen -t rsa -b 2048 -f '.$keyFile.' -N "" -C "deploy@phpci"'); 43 | 44 | if (!empty($output)) { 45 | $pub = file_get_contents($keyFile . '.pub'); 46 | $prv = file_get_contents($keyFile); 47 | 48 | if (!empty($pub)) { 49 | $return['public_key'] = $pub; 50 | } 51 | 52 | if (!empty($prv)) { 53 | $return['private_key'] = $prv; 54 | } 55 | } 56 | 57 | return $return; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /PHPCI/Helper/UnixCommandExecutor.php: -------------------------------------------------------------------------------- 1 | 15 | * @package PHPCI 16 | * @subpackage Web 17 | */ 18 | class User 19 | { 20 | /** 21 | * Proxies method calls through to the current active user model. 22 | * @param $method 23 | * @param array $params 24 | * @return mixed|null 25 | */ 26 | public function __call($method, $params = array()) 27 | { 28 | if (empty($_SESSION['phpci_user'])) { 29 | return null; 30 | } 31 | 32 | $user = $_SESSION['phpci_user']; 33 | 34 | if (!is_object($user)) { 35 | return null; 36 | } 37 | 38 | return call_user_func_array(array($user, $method), $params); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /PHPCI/Helper/WindowsCommandExecutor.php: -------------------------------------------------------------------------------- 1 | build = $build; 42 | // We want to add to any existing saved log information. 43 | $this->logValue = $build->getLog(); 44 | } 45 | 46 | /** 47 | * Write a log entry to the build log. 48 | * @param array $record 49 | */ 50 | protected function write(array $record) 51 | { 52 | $message = (string)$record['message']; 53 | $message = str_replace($this->build->currentBuildPath, '/', $message); 54 | 55 | $this->logValue .= $message . PHP_EOL; 56 | $this->build->setLog($this->logValue); 57 | 58 | Factory::getStore('Build')->save($this->build); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /PHPCI/Logging/LoggedBuildContextTidier.php: -------------------------------------------------------------------------------- 1 | tidyLoggedBuildContext(func_get_arg(0)); 26 | } 27 | 28 | /** 29 | * Removes the build object from the logged record and adds the ID as 30 | * this is more useful to display. 31 | * 32 | * @param array $logRecord 33 | * @return array 34 | */ 35 | protected function tidyLoggedBuildContext(array $logRecord) 36 | { 37 | if (isset($logRecord['context']['build'])) { 38 | $build = $logRecord['context']['build']; 39 | if ($build instanceof Build) { 40 | $logRecord['context']['buildID'] = $build->getId(); 41 | unset($logRecord['context']['build']); 42 | } 43 | } 44 | return $logRecord; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /PHPCI/Logging/OutputLogHandler.php: -------------------------------------------------------------------------------- 1 | output = $output; 39 | } 40 | 41 | /** 42 | * Write a log entry to the terminal. 43 | * @param array $record 44 | */ 45 | protected function write(array $record) 46 | { 47 | $this->output->writeln((string)$record['formatted']); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /PHPCI/Migrations/20140513153133_change_build_keys_migration.php: -------------------------------------------------------------------------------- 1 | table('project'); 13 | $project->renameColumn('git_key', 'ssh_private_key'); 14 | $project->renameColumn('public_key', 'ssh_public_key'); 15 | } 16 | 17 | /** 18 | * Migrate Down. 19 | */ 20 | public function down() 21 | { 22 | $project = $this->table('project'); 23 | $project->renameColumn('ssh_private_key', 'git_key'); 24 | $project->renameColumn('ssh_public_key', 'public_key'); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /PHPCI/Migrations/20140611170618_choose_branch.php: -------------------------------------------------------------------------------- 1 | table('project'); 26 | $project->addColumn('branch', 'string', array( 27 | 'after' => 'reference', 28 | 'limit' => 250 29 | ))->save(); 30 | } 31 | 32 | /** 33 | * Migrate Down. 34 | */ 35 | public function down() 36 | { 37 | $project = $this->table('project'); 38 | $project->removeColumn('branch')->save(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /PHPCI/Migrations/20150131075425_archive_project.php: -------------------------------------------------------------------------------- 1 | table('project'); 13 | $project->addColumn('archived', 'boolean'); 14 | $project->save(); 15 | } 16 | 17 | /** 18 | * Migrate Down. 19 | */ 20 | public function down() 21 | { 22 | $project = $this->table('project'); 23 | $project->removeColumn('archived'); 24 | $project->save(); 25 | } 26 | } -------------------------------------------------------------------------------- /PHPCI/Migrations/20150203105015_fix_column_types.php: -------------------------------------------------------------------------------- 1 | table('build'); 15 | $build->changeColumn('log', 'text', array( 16 | 'null' => true, 17 | 'limit' => MysqlAdapter::TEXT_MEDIUM, 18 | )); 19 | 20 | // Update the build meta value column to MEDIUMTEXT: 21 | $buildMeta = $this->table('build_meta'); 22 | $buildMeta->changeColumn('meta_value', 'text', array( 23 | 'null' => false, 24 | 'limit' => MysqlAdapter::TEXT_MEDIUM, 25 | )); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /PHPCI/Migrations/20150324174958_unique_email_and_name_user_fields.php: -------------------------------------------------------------------------------- 1 | table('user'); 13 | $user_table 14 | ->addIndex('email', array('unique' => true)) 15 | ->addIndex('name', array('unique' => true)) 16 | ->save(); 17 | } 18 | 19 | /** 20 | * Migrate Down. 21 | */ 22 | public function down() 23 | { 24 | $user_table = $this->table('user'); 25 | $user_table 26 | ->removeIndex('email', array('unique' => true)) 27 | ->removeIndex('name', array('unique' => true)) 28 | ->save(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /PHPCI/Migrations/20151008140800_add_project_groups.php: -------------------------------------------------------------------------------- 1 | table('project_group'); 10 | $table->addColumn('title', 'string', array('limit' => 100, 'null' => false)); 11 | $table->save(); 12 | 13 | $group = new \PHPCI\Model\ProjectGroup(); 14 | $group->setTitle('Projects'); 15 | 16 | /** @var \PHPCI\Model\ProjectGroup $group */ 17 | $group = \b8\Store\Factory::getStore('ProjectGroup')->save($group); 18 | 19 | $table = $this->table('project'); 20 | $table->addColumn('group_id', 'integer', array( 21 | 'signed' => true, 22 | 'null' => false, 23 | 'default' => $group->getId(), 24 | )); 25 | 26 | $table->addForeignKey('group_id', 'project_group', 'id', array('delete'=> 'RESTRICT', 'update' => 'CASCADE')); 27 | $table->save(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /PHPCI/Migrations/20151009100610_remove_unique_name_index.php: -------------------------------------------------------------------------------- 1 | table('user'); 31 | 32 | if ($user->hasIndex('name', array('unique' => true))) { 33 | $user->removeIndex('name', array('unique' => true)); 34 | $user->save(); 35 | } 36 | 37 | $user->addIndex('name', array('unique' => false)); 38 | $user->save(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /PHPCI/Migrations/20151014091859_errors_table.php: -------------------------------------------------------------------------------- 1 | table('build_error'); 11 | $table->addColumn('build_id', 'integer', array('signed' => true)); 12 | $table->addColumn('plugin', 'string', array('limit' => 100)); 13 | $table->addColumn('file', 'string', array('limit' => 250, 'null' => true)); 14 | $table->addColumn('line_start', 'integer', array('signed' => false, 'null' => true)); 15 | $table->addColumn('line_end', 'integer', array('signed' => false, 'null' => true)); 16 | $table->addColumn('severity', 'integer', array('signed' => false, 'limit' => MysqlAdapter::INT_TINY)); 17 | $table->addColumn('message', 'string', array('limit' => 250)); 18 | $table->addColumn('created_date', 'datetime'); 19 | $table->addIndex(array('build_id', 'created_date'), array('unique' => false)); 20 | $table->addForeignKey('build_id', 'build', 'id', array('delete'=> 'CASCADE', 'update' => 'CASCADE')); 21 | $table->save(); 22 | 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /PHPCI/Migrations/20160310132732_brach_column_length.php: -------------------------------------------------------------------------------- 1 | table('build'); 16 | $table->changeColumn('branch', 'string', array('limit' => 250)); 17 | } 18 | 19 | /** 20 | * Migrate Down. 21 | */ 22 | public function down() 23 | { 24 | $table = $this->table('build'); 25 | $table->changeColumn('branch', 'string', array('limit' => 50)); 26 | } 27 | 28 | 29 | } 30 | -------------------------------------------------------------------------------- /PHPCI/Migrations/20160623100223_project_table_defaults.php: -------------------------------------------------------------------------------- 1 | table('project') 11 | ->changeColumn('build_config', MysqlAdapter::PHINX_TYPE_TEXT, array('null' => true)) 12 | ->changeColumn('archived', MysqlAdapter::PHINX_TYPE_INTEGER, array( 13 | 'length' => MysqlAdapter::INT_TINY, 14 | 'default' => 0, 15 | )) 16 | ->save(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /PHPCI/Migrations/20161214164202_database_fixes.php: -------------------------------------------------------------------------------- 1 | table('project'); 10 | $project->changeColumn('archived', 'boolean', ['null' => false, 'default' => 0]); 11 | $project->save(); 12 | 13 | $errors = $this->table('build_error'); 14 | $errors->changeColumn('message', 'text'); 15 | $errors->save(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /PHPCI/Migrations/20171027132159_error_hash.php: -------------------------------------------------------------------------------- 1 | table('build_error'); 32 | $errors->addColumn('hash', 'string', ['limit' => 32, 'null' => true, 'default' => null]); 33 | $errors->addColumn('is_new', 'boolean'); 34 | $errors->save(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /PHPCI/Model.php: -------------------------------------------------------------------------------- 1 | 18 | * @package PHPCI 19 | * @subpackage Core 20 | */ 21 | class BitbucketBuild extends RemoteGitBuild 22 | { 23 | /** 24 | * Get link to commit from another source (i.e. Github) 25 | */ 26 | public function getCommitLink() 27 | { 28 | return 'https://bitbucket.org/' . $this->getProject()->getReference() . '/commits/' . $this->getCommitId(); 29 | } 30 | 31 | /** 32 | * Get link to branch from another source (i.e. Github) 33 | */ 34 | public function getBranchLink() 35 | { 36 | return 'https://bitbucket.org/' . $this->getProject()->getReference() . '/src/?at=' . $this->getBranch(); 37 | } 38 | 39 | /** 40 | * Get the URL to be used to clone this remote repository. 41 | */ 42 | protected function getCloneUrl() 43 | { 44 | $key = trim($this->getProject()->getSshPrivateKey()); 45 | 46 | if (!empty($key)) { 47 | return 'git@bitbucket.org:' . $this->getProject()->getReference() . '.git'; 48 | } else { 49 | return 'https://bitbucket.org/' . $this->getProject()->getReference() . '.git'; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /PHPCI/Model/Build/GitlabBuild.php: -------------------------------------------------------------------------------- 1 | 17 | * @package PHPCI 18 | * @subpackage Core 19 | */ 20 | class GitlabBuild extends RemoteGitBuild 21 | { 22 | 23 | /** 24 | * Get link to commit from another source (i.e. Github) 25 | */ 26 | public function getCommitLink() 27 | { 28 | $domain = $this->getProject()->getAccessInformation("domain"); 29 | return 'http://' . $domain . '/' . $this->getProject()->getReference() . '/commit/' . $this->getCommitId(); 30 | } 31 | 32 | /** 33 | * Get link to branch from another source (i.e. Github) 34 | */ 35 | public function getBranchLink() 36 | { 37 | $domain = $this->getProject()->getAccessInformation("domain"); 38 | return 'http://' . $domain . '/' . $this->getProject()->getReference() . '/tree/' . $this->getBranch(); 39 | } 40 | 41 | /** 42 | * Get link to specific file (and line) in a the repo's branch 43 | */ 44 | public function getFileLinkTemplate() 45 | { 46 | return sprintf( 47 | 'http://%s/%s/blob/%s/{FILE}#L{LINE}', 48 | $this->getProject()->getAccessInformation("domain"), 49 | $this->getProject()->getReference(), 50 | $this->getCommitId() 51 | ); 52 | } 53 | 54 | /** 55 | * Get the URL to be used to clone this remote repository. 56 | */ 57 | protected function getCloneUrl() 58 | { 59 | $key = trim($this->getProject()->getSshPrivateKey()); 60 | 61 | if (!empty($key)) { 62 | $user = $this->getProject()->getAccessInformation("user"); 63 | $domain = $this->getProject()->getAccessInformation("domain"); 64 | $port = $this->getProject()->getAccessInformation('port'); 65 | 66 | $url = $user . '@' . $domain . ':'; 67 | 68 | if (!empty($port)) { 69 | $url .= $port . '/'; 70 | } 71 | 72 | $url .= $this->getProject()->getReference() . '.git'; 73 | 74 | return $url; 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /PHPCI/Model/BuildError.php: -------------------------------------------------------------------------------- 1 | getSeverity()) { 31 | case self::SEVERITY_CRITICAL: 32 | return 'critical'; 33 | 34 | case self::SEVERITY_HIGH: 35 | return 'high'; 36 | 37 | case self::SEVERITY_NORMAL: 38 | return 'normal'; 39 | 40 | case self::SEVERITY_LOW: 41 | return 'low'; 42 | } 43 | } 44 | 45 | /** 46 | * Get the class to apply to HTML elements representing this error. 47 | * @return string 48 | */ 49 | public function getSeverityClass() 50 | { 51 | switch ($this->getSeverity()) { 52 | case self::SEVERITY_CRITICAL: 53 | return 'danger'; 54 | 55 | case self::SEVERITY_HIGH: 56 | return 'warning'; 57 | 58 | case self::SEVERITY_NORMAL: 59 | return 'info'; 60 | 61 | case self::SEVERITY_LOW: 62 | return 'default'; 63 | } 64 | } 65 | 66 | public function hash() 67 | { 68 | $hash = $this->getPlugin() . '|' . $this->getFile() . '|' . $this->getLineStart(); 69 | $hash .= '|' . $this->getLineEnd() . '|' . $this->getSeverity() . '|' . $this->getMessage(); 70 | 71 | $this->setHash(md5($hash)); 72 | 73 | /** @var Store\BuildErrorStore $errorStore */ 74 | $errorStore = Factory::getStore('BuildError'); 75 | 76 | $this->setIsNew($errorStore->getIsNewError($this->getHash())); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /PHPCI/Model/BuildMeta.php: -------------------------------------------------------------------------------- 1 | 18 | * @package PHPCI 19 | * @subpackage Core 20 | */ 21 | class User extends UserBase 22 | { 23 | // This class has been left blank so that you can modify it - changes in this file will not be overwritten. 24 | } 25 | -------------------------------------------------------------------------------- /PHPCI/Plugin.php: -------------------------------------------------------------------------------- 1 | 15 | */ 16 | interface Plugin 17 | { 18 | public function execute(); 19 | } 20 | -------------------------------------------------------------------------------- /PHPCI/Plugin/CleanBuild.php: -------------------------------------------------------------------------------- 1 | 19 | * @package PHPCI 20 | * @subpackage Plugins 21 | */ 22 | class CleanBuild implements \PHPCI\Plugin 23 | { 24 | protected $remove; 25 | protected $phpci; 26 | protected $build; 27 | 28 | /** 29 | * Standard Constructor 30 | * 31 | * $options['directory'] Output Directory. Default: %BUILDPATH% 32 | * $options['filename'] Phar Filename. Default: build.phar 33 | * $options['regexp'] Regular Expression Filename Capture. Default: /\.php$/ 34 | * $options['stub'] Stub Content. No Default Value 35 | * 36 | * @param Builder $phpci 37 | * @param Build $build 38 | * @param array $options 39 | */ 40 | public function __construct(Builder $phpci, Build $build, array $options = array()) 41 | { 42 | $this->phpci = $phpci; 43 | $this->build = $build; 44 | $this->remove = isset($options['remove']) && is_array($options['remove']) ? $options['remove'] : array(); 45 | } 46 | 47 | /** 48 | * Executes Composer and runs a specified command (e.g. install / update) 49 | */ 50 | public function execute() 51 | { 52 | $cmd = 'rm -Rf "%s"'; 53 | if (IS_WIN) { 54 | $cmd = 'rmdir /S /Q "%s"'; 55 | } 56 | $this->phpci->executeCommand($cmd, $this->phpci->buildPath . 'composer.phar'); 57 | $this->phpci->executeCommand($cmd, $this->phpci->buildPath . 'composer.lock'); 58 | 59 | $success = true; 60 | 61 | foreach ($this->remove as $file) { 62 | $ok = $this->phpci->executeCommand($cmd, $this->phpci->buildPath . $file); 63 | 64 | if (!$ok) { 65 | $success = false; 66 | } 67 | } 68 | 69 | return $success; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /PHPCI/Plugin/Deployer.php: -------------------------------------------------------------------------------- 1 | 19 | * @package PHPCI 20 | * @subpackage Plugins 21 | */ 22 | class Deployer implements \PHPCI\Plugin 23 | { 24 | protected $webhookUrl; 25 | protected $reason; 26 | protected $updateOnly; 27 | 28 | /** 29 | * Set up the plugin, configure options, etc. 30 | * @param Builder $phpci 31 | * @param Build $build 32 | * @param array $options 33 | */ 34 | public function __construct(Builder $phpci, Build $build, array $options = array()) 35 | { 36 | $this->phpci = $phpci; 37 | $this->build = $build; 38 | $this->reason = 'PHPCI Build #%BUILD% - %COMMIT_MESSAGE%'; 39 | 40 | if (isset($options['webhook_url'])) { 41 | $this->webhookUrl = $options['webhook_url']; 42 | } 43 | 44 | if (isset($options['reason'])) { 45 | $this->reason = $options['reason']; 46 | } 47 | 48 | $this->updateOnly = isset($options['update_only']) ? (bool) $options['update_only'] : true; 49 | } 50 | 51 | /** 52 | * Copies files from the root of the build directory into the target folder 53 | */ 54 | public function execute() 55 | { 56 | if (empty($this->webhookUrl)) { 57 | $this->phpci->logFailure('You must specify a webhook URL.'); 58 | return false; 59 | } 60 | 61 | $http = new HttpClient(); 62 | 63 | $response = $http->post($this->webhookUrl, array( 64 | 'reason' => $this->phpci->interpolate($this->reason), 65 | 'source' => 'PHPCI', 66 | 'url' => $this->phpci->interpolate('%BUILD_URI%'), 67 | 'branch' => $this->phpci->interpolate('%BRANCH%'), 68 | 'commit' => $this->phpci->interpolate('%COMMIT%'), 69 | 'update_only' => $this->updateOnly, 70 | )); 71 | 72 | return $response['success']; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /PHPCI/Plugin/Env.php: -------------------------------------------------------------------------------- 1 | 19 | * @package PHPCI 20 | * @subpackage Plugins 21 | */ 22 | class Env implements \PHPCI\Plugin 23 | { 24 | protected $phpci; 25 | protected $build; 26 | protected $env_vars; 27 | 28 | /** 29 | * Set up the plugin, configure options, etc. 30 | * @param Builder $phpci 31 | * @param Build $build 32 | * @param array $options 33 | */ 34 | public function __construct(Builder $phpci, Build $build, array $options = array()) 35 | { 36 | $this->phpci = $phpci; 37 | $this->build = $build; 38 | $this->env_vars = $options; 39 | } 40 | 41 | /** 42 | * Adds the specified environment variables to the builder environment 43 | */ 44 | public function execute() 45 | { 46 | $success = true; 47 | foreach ($this->env_vars as $key => $value) { 48 | if (is_numeric($key)) { 49 | // This allows the developer to specify env vars like " - FOO=bar" or " - FOO: bar" 50 | $env_var = is_array($value)? key($value).'='.current($value): $value; 51 | } else { 52 | // This allows the standard syntax: "FOO: bar" 53 | $env_var = "$key=$value"; 54 | } 55 | 56 | if (!putenv($this->phpci->interpolate($env_var))) { 57 | $success = false; 58 | $this->phpci->logFailure(Lang::get('unable_to_set_env')); 59 | } 60 | } 61 | return $success; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /PHPCI/Plugin/Pgsql.php: -------------------------------------------------------------------------------- 1 | 19 | * @package PHPCI 20 | * @subpackage Plugins 21 | */ 22 | class Pgsql implements \PHPCI\Plugin 23 | { 24 | /** 25 | * @var \PHPCI\Builder 26 | */ 27 | protected $phpci; 28 | 29 | /** 30 | * @var \PHPCI\Model\Build 31 | */ 32 | protected $build; 33 | 34 | /** 35 | * @var array 36 | */ 37 | protected $queries = array(); 38 | 39 | /** 40 | * @var string 41 | */ 42 | protected $host; 43 | 44 | /** 45 | * @var string 46 | */ 47 | protected $user; 48 | 49 | /** 50 | * @var string 51 | */ 52 | protected $pass; 53 | 54 | /** 55 | * @param Builder $phpci 56 | * @param Build $build 57 | * @param array $options 58 | */ 59 | public function __construct(Builder $phpci, Build $build, array $options = array()) 60 | { 61 | $this->phpci = $phpci; 62 | $this->build = $build; 63 | $this->queries = $options; 64 | 65 | $buildSettings = $phpci->getConfig('build_settings'); 66 | 67 | if (isset($buildSettings['pgsql'])) { 68 | $sql = $buildSettings['pgsql']; 69 | $this->host = $sql['host']; 70 | $this->user = $sql['user']; 71 | $this->pass = $sql['pass']; 72 | } 73 | } 74 | 75 | /** 76 | * Connects to PgSQL and runs a specified set of queries. 77 | * @return boolean 78 | */ 79 | public function execute() 80 | { 81 | try { 82 | $opts = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION); 83 | $pdo = new PDO('pgsql:host=' . $this->host, $this->user, $this->pass, $opts); 84 | 85 | foreach ($this->queries as $query) { 86 | $pdo->query($this->phpci->interpolate($query)); 87 | } 88 | } catch (\Exception $ex) { 89 | $this->phpci->logFailure($ex->getMessage()); 90 | return false; 91 | } 92 | return true; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /PHPCI/Plugin/Sqlite.php: -------------------------------------------------------------------------------- 1 | 19 | * @package PHPCI 20 | * @subpackage Plugins 21 | */ 22 | class Sqlite implements \PHPCI\Plugin 23 | { 24 | /** 25 | * @var \PHPCI\Builder 26 | */ 27 | protected $phpci; 28 | 29 | /** 30 | * @var \PHPCI\Model\Build 31 | */ 32 | protected $build; 33 | 34 | /** 35 | * @var array 36 | */ 37 | protected $queries = array(); 38 | 39 | /** 40 | * @var string 41 | */ 42 | protected $path; 43 | 44 | /** 45 | * @param Builder $phpci 46 | * @param Build $build 47 | * @param array $options 48 | */ 49 | public function __construct(Builder $phpci, Build $build, array $options = array()) 50 | { 51 | $this->phpci = $phpci; 52 | $this->build = $build; 53 | $this->queries = $options; 54 | $buildSettings = $phpci->getConfig('build_settings'); 55 | 56 | if (isset($buildSettings['sqlite'])) { 57 | $sql = $buildSettings['sqlite']; 58 | $this->path = $sql['path']; 59 | } 60 | } 61 | 62 | /** 63 | * Connects to SQLite and runs a specified set of queries. 64 | * @return boolean 65 | */ 66 | public function execute() 67 | { 68 | try { 69 | $opts = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION); 70 | $pdo = new PDO('sqlite:' . $this->path, $opts); 71 | 72 | foreach ($this->queries as $query) { 73 | $pdo->query($this->phpci->interpolate($query)); 74 | } 75 | } catch (\Exception $ex) { 76 | $this->phpci->logFailure($ex->getMessage()); 77 | return false; 78 | } 79 | return true; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /PHPCI/Plugin/Util/InstalledPluginInformation.php: -------------------------------------------------------------------------------- 1 | pluginInformations[] = $information; 23 | } 24 | 25 | /** 26 | * Returns an array of objects. Each one represents an available plugin 27 | * and will have the following properties: 28 | * name - The friendly name of the plugin (may be an empty string) 29 | * class - The class of the plugin (will include namespace) 30 | * @return \stdClass[] 31 | */ 32 | public function getInstalledPlugins() 33 | { 34 | $arr = array(); 35 | 36 | foreach ($this->pluginInformations as $single) { 37 | $arr = array_merge($arr, $single->getInstalledPlugins()); 38 | } 39 | 40 | return $arr; 41 | } 42 | 43 | /** 44 | * Returns an array of all the class names of plugins that have been 45 | * loaded. 46 | * 47 | * @return string[] 48 | */ 49 | public function getPluginClasses() 50 | { 51 | $arr = array(); 52 | 53 | foreach ($this->pluginInformations as $single) { 54 | $arr = array_merge($arr, $single->getPluginClasses()); 55 | } 56 | 57 | return $arr; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /PHPCI/Plugin/Util/TestResultParsers/ParserInterface.php: -------------------------------------------------------------------------------- 1 | 18 | * @package PHPCI 19 | * @subpackage Plugins 20 | */ 21 | class Wipe implements \PHPCI\Plugin 22 | { 23 | /** 24 | * @var \PHPCI\Builder 25 | */ 26 | protected $phpci; 27 | 28 | /** 29 | * @var \PHPCI\Model\Build 30 | */ 31 | protected $build; 32 | 33 | protected $directory; 34 | 35 | /** 36 | * Set up the plugin, configure options, etc. 37 | * @param Builder $phpci 38 | * @param Build $build 39 | * @param array $options 40 | */ 41 | public function __construct(Builder $phpci, Build $build, array $options = array()) 42 | { 43 | $path = $phpci->buildPath; 44 | $this->phpci = $phpci; 45 | $this->build = $build; 46 | $this->directory = isset($options['directory']) ? $this->phpci->interpolate($options['directory']) : $path; 47 | } 48 | 49 | /** 50 | * Wipes a directory's contents 51 | */ 52 | public function execute() 53 | { 54 | $build = $this->phpci->buildPath; 55 | 56 | if ($this->directory == $build || empty($this->directory)) { 57 | return true; 58 | } 59 | if (is_dir($this->directory)) { 60 | $cmd = 'rm -Rf "%s"'; 61 | if (IS_WIN) { 62 | $cmd = 'rmdir /S /Q "%s"'; 63 | } 64 | return $this->phpci->executeCommand($cmd, $this->directory); 65 | } 66 | return true; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /PHPCI/ProcessControl/Factory.php: -------------------------------------------------------------------------------- 1 | 16 | */ 17 | class Factory 18 | { 19 | /** 20 | * ProcessControl singleton. 21 | * 22 | * @var ProcessControlInterface 23 | */ 24 | protected static $instance = null; 25 | 26 | /** 27 | * Returns the ProcessControl singleton. 28 | * 29 | * @return ProcessControlInterface 30 | */ 31 | public static function getInstance() 32 | { 33 | if (static::$instance === null) { 34 | static::$instance = static::createProcessControl(); 35 | } 36 | return static::$instance; 37 | } 38 | 39 | /** 40 | * Create a ProcessControl depending on available extensions and the underlying OS. 41 | * 42 | * Check PosixProcessControl, WindowsProcessControl and UnixProcessControl, in that order. 43 | * 44 | * @return ProcessControlInterface 45 | * 46 | * @internal 47 | */ 48 | public static function createProcessControl() 49 | { 50 | switch (true) { 51 | case PosixProcessControl::isAvailable(): 52 | return new PosixProcessControl(); 53 | 54 | case WindowsProcessControl::isAvailable(): 55 | return new WindowsProcessControl(); 56 | 57 | case UnixProcessControl::isAvailable(): 58 | return new UnixProcessControl(); 59 | } 60 | 61 | throw new \Exception("No ProcessControl implementation available."); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /PHPCI/ProcessControl/PosixProcessControl.php: -------------------------------------------------------------------------------- 1 | 16 | */ 17 | class PosixProcessControl implements ProcessControlInterface 18 | { 19 | /** 20 | * 21 | * @param int $pid 22 | * @return bool 23 | */ 24 | public function isRunning($pid) 25 | { 26 | // Signal "0" is not sent to the process, but posix_kill checks the process anyway; 27 | return posix_kill($pid, 0); 28 | } 29 | 30 | /** 31 | * Sends a TERMINATE or KILL signal to the process using posix_kill. 32 | * 33 | * @param int $pid 34 | * @param bool $forcefully Whether to send TERMINATE (false) or KILL (true). 35 | */ 36 | public function kill($pid, $forcefully = false) 37 | { 38 | posix_kill($pid, $forcefully ? 9 : 15); 39 | } 40 | 41 | /** 42 | * Check whether this posix_kill is available. 43 | * 44 | * @return bool 45 | * 46 | * @internal 47 | */ 48 | public static function isAvailable() 49 | { 50 | return function_exists('posix_kill'); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /PHPCI/ProcessControl/ProcessControlInterface.php: -------------------------------------------------------------------------------- 1 | 16 | */ 17 | interface ProcessControlInterface 18 | { 19 | /** Checks if a process exists. 20 | * 21 | * @param int $pid The process identifier. 22 | * 23 | * @return boolean true is the process is running, else false. 24 | */ 25 | public function isRunning($pid); 26 | 27 | /** Terminate a running process. 28 | * 29 | * @param int $pid The process identifier. 30 | * @param bool $forcefully Whether to gently (false) or forcefully (true) terminate the process. 31 | */ 32 | public function kill($pid, $forcefully = false); 33 | } 34 | -------------------------------------------------------------------------------- /PHPCI/ProcessControl/UnixProcessControl.php: -------------------------------------------------------------------------------- 1 | 16 | */ 17 | class UnixProcessControl implements ProcessControlInterface 18 | { 19 | /** 20 | * Check process using the "ps" command. 21 | * 22 | * @param int $pid 23 | * @return boolean 24 | */ 25 | public function isRunning($pid) 26 | { 27 | $output = $exitCode = null; 28 | exec(sprintf("ps %d", $pid), $output, $exitCode); 29 | return $exitCode === 0; 30 | } 31 | 32 | /** 33 | * Sends a signal using the "kill" command. 34 | * 35 | * @param int $pid 36 | * @param bool $forcefully 37 | */ 38 | public function kill($pid, $forcefully = false) 39 | { 40 | exec(sprintf("kill -%d %d", $forcefully ? 9 : 15, $pid)); 41 | } 42 | 43 | /** 44 | * Check whether the commands "ps" and "kill" are available. 45 | * 46 | * @return bool 47 | * 48 | * @internal 49 | */ 50 | public static function isAvailable() 51 | { 52 | return DIRECTORY_SEPARATOR === '/' && exec("which ps") && exec("which kill"); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /PHPCI/ProcessControl/WindowsProcessControl.php: -------------------------------------------------------------------------------- 1 | 16 | */ 17 | class WindowsProcessControl implements ProcessControlInterface 18 | { 19 | /** 20 | * Check if the process is running using the "tasklist" command. 21 | * 22 | * @param type $pid 23 | * @return bool 24 | */ 25 | public function isRunning($pid) 26 | { 27 | $lastLine = exec(sprintf('tasklist /fi "PID eq %d" /nh /fo csv 2>nul:', $pid)); 28 | $record = str_getcsv($lastLine); 29 | return isset($record[1]) && intval($record[1]) === $pid; 30 | } 31 | 32 | /** 33 | * Terminate the process using the "taskkill" command. 34 | * 35 | * @param type $pid 36 | * @param bool $forcefully 37 | */ 38 | public function kill($pid, $forcefully = false) 39 | { 40 | exec(sprintf("taskkill /t /pid %d %s 2>nul:", $pid, $forcefully ? '/f' : '')); 41 | } 42 | 43 | /** 44 | * Check whether the commands "tasklist" and "taskkill" are available. 45 | * 46 | * @return bool 47 | * 48 | * @internal 49 | */ 50 | public static function isAvailable() 51 | { 52 | return DIRECTORY_SEPARATOR === '\\' && exec("where tasklist") && exec("where taskkill"); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /PHPCI/Service/UserService.php: -------------------------------------------------------------------------------- 1 | store = $store; 33 | } 34 | 35 | /** 36 | * Create a new user within PHPCI. 37 | * @param $name 38 | * @param $emailAddress 39 | * @param $password 40 | * @param bool $isAdmin 41 | * @return \PHPCI\Model\User 42 | */ 43 | public function createUser($name, $emailAddress, $password, $isAdmin = false) 44 | { 45 | $user = new User(); 46 | $user->setName($name); 47 | $user->setEmail($emailAddress); 48 | $user->setHash(password_hash($password, PASSWORD_DEFAULT)); 49 | $user->setIsAdmin(($isAdmin ? 1 : 0)); 50 | 51 | return $this->store->save($user); 52 | } 53 | 54 | /** 55 | * Update a user. 56 | * @param User $user 57 | * @param $name 58 | * @param $emailAddress 59 | * @param null $password 60 | * @param null $isAdmin 61 | * @return \PHPCI\Model\User 62 | */ 63 | public function updateUser(User $user, $name, $emailAddress, $password = null, $isAdmin = null) 64 | { 65 | $user->setName($name); 66 | $user->setEmail($emailAddress); 67 | 68 | if (!empty($password)) { 69 | $user->setHash(password_hash($password, PASSWORD_DEFAULT)); 70 | } 71 | 72 | if (!is_null($isAdmin)) { 73 | $user->setIsAdmin(($isAdmin ? 1 : 0)); 74 | } 75 | 76 | return $this->store->save($user); 77 | } 78 | 79 | /** 80 | * Delete a user. 81 | * @param User $user 82 | * @return bool 83 | */ 84 | public function deleteUser(User $user) 85 | { 86 | return $this->store->delete($user); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /PHPCI/Store.php: -------------------------------------------------------------------------------- 1 | getById($value, $useConnection); 29 | } 30 | 31 | /** 32 | * Get a single ProjectGroup by Id. 33 | * @return null|ProjectGroup 34 | */ 35 | public function getById($value, $useConnection = 'read') 36 | { 37 | if (is_null($value)) { 38 | throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.'); 39 | } 40 | 41 | $query = 'SELECT * FROM `project_group` WHERE `id` = :id LIMIT 1'; 42 | $stmt = Database::getConnection($useConnection)->prepare($query); 43 | $stmt->bindValue(':id', $value); 44 | 45 | if ($stmt->execute()) { 46 | if ($data = $stmt->fetch(\PDO::FETCH_ASSOC)) { 47 | return new ProjectGroup($data); 48 | } 49 | } 50 | 51 | return null; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /PHPCI/Store/BuildMetaStore.php: -------------------------------------------------------------------------------- 1 | prepare($query); 35 | 36 | $stmt->bindValue(':limit', $limit, \PDO::PARAM_INT); 37 | 38 | if ($stmt->execute()) { 39 | $res = $stmt->fetchAll(\PDO::FETCH_ASSOC); 40 | 41 | $map = function ($item) { 42 | return new BuildMeta($item); 43 | }; 44 | $rtn = array_map($map, $res); 45 | 46 | return $rtn; 47 | } else { 48 | return array(); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /PHPCI/Store/ProjectGroupStore.php: -------------------------------------------------------------------------------- 1 | 17 | * @package PHPCI 18 | * @subpackage Core 19 | */ 20 | class UserStore extends UserStoreBase 21 | { 22 | // This class has been left blank so that you can modify it - changes in this file will not be overwritten. 23 | } 24 | -------------------------------------------------------------------------------- /PHPCI/View/Build/errors.phtml: -------------------------------------------------------------------------------- 1 | getFileLinkTemplate(); 5 | 6 | /** @var \PHPCI\Model\BuildError $error */ 7 | foreach ($errors as $error): 8 | 9 | $link = str_replace('{FILE}', $error->getFile(), $linkTemplate); 10 | $link = str_replace('{LINE}', $error->getLineStart(), $link); 11 | $link = str_replace('{LINE_END}', $error->getLineEnd(), $link); 12 | ?> 13 | 14 | 15 | 16 | getIsNew()): ?> 17 | New 18 | 19 | 20 | 21 | 22 | getSeverityString()); ?> 23 | 24 | 25 | getPlugin()); ?> 26 | getFile(); ?> 27 | 28 | 29 | getLineStart() == $error->getLineEnd() || !$error->getLineEnd()) { 31 | print $error->getLineStart(); 32 | } else { 33 | print $error->getLineStart() . ' - ' . $error->getLineEnd(); 34 | } 35 | ?> 36 | 37 | 38 | getMessage(); ?> 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /PHPCI/View/Build/header-row.phtml: -------------------------------------------------------------------------------- 1 | 2 |
  • 3 | 4 | getCommitterEmail()): ?> 5 |
    6 | 7 |
    8 | 9 | 10 |

    11 | getProject()->getTitle(); ?> 12 | 13 | getStatus() == \PHPCI\Model\Build::STATUS_NEW): ?> 14 | getCreated()->format('H:i')); ?> 15 | getStatus() == \PHPCI\Model\Build::STATUS_RUNNING): ?> 16 | getStarted()->format('H:i')); ?> 17 | 18 |

    19 |

    getBranch()); ?>

    20 |
    21 |
  • -------------------------------------------------------------------------------- /PHPCI/View/Email/layout.phtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 |
    11 |
    12 |
    getTitle(); ?> - Build #getId(); ?>
    13 |
    14 |

    15 | Your commit getCommitId(); ?> generated a 16 | isSuccessful() ? 'successful' : 'failed'; ?> build in project 17 | getTitle(); ?>. 18 |

    19 | 20 |
    21 | 25 |
    26 |
    27 | 28 | 29 | -------------------------------------------------------------------------------- /PHPCI/View/Email/long.phtml: -------------------------------------------------------------------------------- 1 |

    getCommitMessage(); ?>

    2 |
    getLog()); ?>
    3 | -------------------------------------------------------------------------------- /PHPCI/View/Email/short.phtml: -------------------------------------------------------------------------------- 1 |

    getCommitMessage(); ?>

    2 | -------------------------------------------------------------------------------- /PHPCI/View/Group/edit.phtml: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |

    Add / Edit Group

    4 |
    5 | 6 |
    7 | 8 |
    9 |
    -------------------------------------------------------------------------------- /PHPCI/View/Group/index.phtml: -------------------------------------------------------------------------------- 1 |
    2 | 3 | Add Group 4 | 5 |
    6 | 7 | 8 |
    9 |
    10 |

    Project Groups

    11 |
    12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 37 | 38 | 39 | 40 |
    TitleProjects
    27 | 28 | Edit 29 | 30 | 31 | 32 | 33 | Delete 34 | 35 | 36 |
    41 |
    -------------------------------------------------------------------------------- /PHPCI/View/Plugin/index.phtml: -------------------------------------------------------------------------------- 1 | 2 | 3 |
    4 |

    Adding requirements to the PHPCI composer.json file is no longer recommended as a method of installing your required testing tools.
    5 | For this reason, we have removed the ability for PHPCI to modify the composer.json file for you. 6 | We recommend that you install testing tools using your project's own composer.json file, by adding them to the "require-dev" section of the file.

    7 |
    8 | 9 |
    10 |
    11 |
    12 |
    13 |

    14 |
    15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 |
    name; ?>class; ?>source; ?>
    34 |
    35 |
    36 | 37 |
    38 |
    39 |
    40 |

    41 |
    42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | $version): ?> 53 | 54 | 55 | 56 | 57 | 58 | 59 |
    60 |
    61 | 62 |
    63 |
    64 | 65 | -------------------------------------------------------------------------------- /PHPCI/View/ProjectForm.phtml: -------------------------------------------------------------------------------- 1 | 2 |
    3 | 4 |
    5 |
    6 |
    7 |

    8 |
    9 | 10 |
    11 | 12 |
    13 |
    14 |
    15 | 16 | 17 |
    18 |
    19 |
    20 |

    21 | 22 | 23 |
    24 |
    25 |
    26 | 27 | 28 |
    29 | 30 | 47 | -------------------------------------------------------------------------------- /PHPCI/View/Session/forgotPassword.phtml: -------------------------------------------------------------------------------- 1 | 2 | 3 |

    4 | 5 |

    6 | 7 | 8 |
    9 | 10 |
    11 | 12 |
    13 | 14 |
    15 | 16 | 17 |
    18 |
    19 |
    20 | 21 | 22 |
    23 | 24 |
    25 | 26 |
    27 |
    28 |
    29 | 30 | 31 | -------------------------------------------------------------------------------- /PHPCI/View/Session/login.phtml: -------------------------------------------------------------------------------- 1 | 2 | 3 |

    4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /PHPCI/View/Session/resetPassword.phtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
    5 | 6 |
    7 | 8 |
    9 |
    10 |
    11 | 12 | 13 |
    14 | 15 |
    16 | 17 |
    18 |
    19 |
    20 | 21 |
    22 | 23 |
    24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /PHPCI/View/User/profile.phtml: -------------------------------------------------------------------------------- 1 | 2 | 3 |

    4 | 5 | 6 |
    7 |
    8 |

    9 |
    10 |
    11 | 12 |
    13 |
    14 | 15 | -------------------------------------------------------------------------------- /PHPCI/View/UserForm.phtml: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |
    4 |
    5 | 6 |
    7 |
    8 |
    9 |
    10 | -------------------------------------------------------------------------------- /PHPCI/View/exception.phtml: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |

    Sorry, there was a problem

    4 |
    5 | 6 |
    7 | getMessage(); ?> 8 |
    9 |
    -------------------------------------------------------------------------------- /PHPCI/ZeroConfigPlugin.php: -------------------------------------------------------------------------------- 1 | 17 | */ 18 | interface ZeroConfigPlugin 19 | { 20 | public static function canExecute($stage, Builder $builder, Build $build); 21 | } 22 | -------------------------------------------------------------------------------- /PHPCI/build/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | PHPCI 2 | ===== 3 | 4 | PHPCI is a free and open source (BSD License) continuous integration tool specifically designed for PHP. We've built it with simplicity in mind, so whilst it doesn't do *everything* Jenkins can do, it is a breeze to set up and use. 5 | 6 | 7 | ## What it does: 8 | * Clones your project from Github, Bitbucket or a local path 9 | * Allows you to set up and tear down test databases. 10 | * Installs your project's Composer dependencies. 11 | * Runs through any combination of the [supported plugins](https://docs.phptesting.org/en/latest/#plugins). 12 | * You can mark directories for the plugins to ignore. 13 | * You can mark certain plugins as being allowed to fail (but still run.) 14 | 15 | ### What it doesn't do (yet): 16 | * Virtualised testing. 17 | * Multiple PHP-version tests. 18 | * Install PEAR or PECL extensions. 19 | * Deployments - We strongly recommend using [Deployer](http://phpdeployment.org) 20 | 21 | ## Getting Started: 22 | We've got documentation on our website on [installing PHPCI](https://docs.phptesting.org/en/latest/installing-phpci/) and [adding support for PHPCI to your projects](https://docs.phptesting.org/en/latest/adding-phpci-support-to-your-projects/). 23 | 24 | ## Contributing 25 | Contributions from others would be very much appreciated! Please read our [guide to contributing](https://github.com/dancryer/PHPCI/blob/master/.github/CONTRIBUTING.md) for more information on how to get involved. 26 | 27 | ## Questions? 28 | Your best place to go is the [mailing list](https://groups.google.com/forum/#!forum/php-ci). If you're already a member of the mailing list, you can simply email php-ci@googlegroups.com. 29 | -------------------------------------------------------------------------------- /Tests/PHPCI/Controller/WebhookControllerTest.php: -------------------------------------------------------------------------------- 1 | prophesize('b8\Config')->reveal(), 21 | $this->prophesize('b8\Http\Request')->reveal(), 22 | $this->prophesize('b8\Http\Response')->reveal() 23 | ); 24 | 25 | $error = $webController->handleAction('test', []); 26 | 27 | $this->assertInstanceOf('b8\Http\Response\JsonResponse', $error); 28 | 29 | $responseData = $error->getData(); 30 | $this->assertEquals(500, $responseData['code']); 31 | 32 | $this->assertEquals('failed', $responseData['body']['status']); 33 | 34 | $this->assertEquals('application/json', $responseData['headers']['Content-Type']); 35 | 36 | // @todo: we can't text the result is JSON file with 37 | // $this->assertJson((string) $error); 38 | // since the flush method automatically add the header and break the 39 | // testing framework. 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Tests/PHPCI/Helper/AnsiConverterTest.php: -------------------------------------------------------------------------------- 1 | markTestSkipped('External library do not support PHP 5.3'); 22 | } 23 | } 24 | 25 | public function testConvert_convertToHtml() 26 | { 27 | $input = "\e[31mThis is red !\e[0m"; 28 | 29 | $expectedOutput = 'This is red !'; 30 | 31 | $actualOutput = AnsiConverter::convert($input); 32 | 33 | $this->assertEquals($expectedOutput, $actualOutput); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Tests/PHPCI/Helper/BuildInterpolatorTest.php: -------------------------------------------------------------------------------- 1 | testedInterpolator = new BuildInterpolator(); 26 | } 27 | 28 | public function testInterpolate_LeavesStringsUnchangedByDefault() 29 | { 30 | $string = "Hello World"; 31 | $expectedOutput = "Hello World"; 32 | 33 | $actualOutput = $this->testedInterpolator->interpolate($string); 34 | 35 | $this->assertEquals($expectedOutput, $actualOutput); 36 | } 37 | 38 | public function testInterpolate_LeavesStringsUnchangedWhenBuildIsSet() 39 | { 40 | $build = $this->prophesize('PHPCI\\Model\\Build')->reveal(); 41 | 42 | $string = "Hello World"; 43 | $expectedOutput = "Hello World"; 44 | 45 | $this->testedInterpolator->setupInterpolationVars( 46 | $build, 47 | "/buildpath/", 48 | "phpci.com" 49 | ); 50 | 51 | $actualOutput = $this->testedInterpolator->interpolate($string); 52 | 53 | $this->assertEquals($expectedOutput, $actualOutput); 54 | } 55 | } 56 | 57 | -------------------------------------------------------------------------------- /Tests/PHPCI/Helper/LangTest.php: -------------------------------------------------------------------------------- 1 | prophesize('DateTime'); 21 | $dateTime->format(DateTime::ISO8601)->willReturn("ISODATE"); 22 | $dateTime->format(DateTime::RFC2822)->willReturn("RFCDATE"); 23 | 24 | $this->assertEquals('', Lang::formatDateTime($dateTime->reveal(), 'FORMAT')); 25 | } 26 | 27 | public function testLang_UseDefaultFormat() 28 | { 29 | $dateTime = $this->prophesize('DateTime'); 30 | $dateTime->format(DateTime::ISO8601)->willReturn("ISODATE"); 31 | $dateTime->format(DateTime::RFC2822)->willReturn("RFCDATE"); 32 | 33 | $this->assertEquals('', Lang::formatDateTime($dateTime->reveal())); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Tests/PHPCI/Model/BuildTest.php: -------------------------------------------------------------------------------- 1 | 20 | */ 21 | class BuildTest extends \PHPUnit_Framework_TestCase 22 | { 23 | public function setUp() 24 | { 25 | } 26 | 27 | public function testExecute_TestIsAValidModel() 28 | { 29 | $build = new Build(); 30 | $this->assertTrue($build instanceof \b8\Model); 31 | $this->assertTrue($build instanceof Model); 32 | $this->assertTrue($build instanceof Model\Base\BuildBase); 33 | } 34 | 35 | public function testExecute_TestBaseBuildDefaults() 36 | { 37 | $build = new Build(); 38 | $this->assertEquals('#', $build->getCommitLink()); 39 | $this->assertEquals('#', $build->getBranchLink()); 40 | $this->assertEquals(null, $build->getFileLinkTemplate()); 41 | } 42 | 43 | public function testExecute_TestIsSuccessful() 44 | { 45 | $build = new Build(); 46 | $build->setStatus(Build::STATUS_NEW); 47 | $this->assertFalse($build->isSuccessful()); 48 | 49 | $build->setStatus(Build::STATUS_RUNNING); 50 | $this->assertFalse($build->isSuccessful()); 51 | 52 | $build->setStatus(Build::STATUS_FAILED); 53 | $this->assertFalse($build->isSuccessful()); 54 | 55 | $build->setStatus(Build::STATUS_SUCCESS); 56 | $this->assertTrue($build->isSuccessful()); 57 | } 58 | 59 | public function testExecute_TestBuildExtra() 60 | { 61 | $info = array( 62 | 'item1' => 'Item One', 63 | 'item2' => 2, 64 | ); 65 | 66 | $build = new Build(); 67 | $build->setExtra(json_encode($info)); 68 | 69 | $this->assertEquals('Item One', $build->getExtra('item1')); 70 | $this->assertEquals(2, $build->getExtra('item2')); 71 | $this->assertNull($build->getExtra('item3')); 72 | $this->assertEquals($info, $build->getExtra()); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /Tests/PHPCI/Plugin/Util/ComposerPluginInformationTest.php: -------------------------------------------------------------------------------- 1 | testedInformation = ComposerPluginInformation::buildFromYaml($file); 25 | } 26 | 27 | protected function phpciSetup() 28 | { 29 | $this->setUpFromFile( 30 | __DIR__ . "/../../../../vendor/composer/installed.json" 31 | ); 32 | } 33 | 34 | public function testBuildFromYaml_ReturnsInstance() 35 | { 36 | $this->phpciSetup(); 37 | $this->assertInstanceOf( 38 | '\PHPCI\Plugin\Util\ComposerPluginInformation', 39 | $this->testedInformation 40 | ); 41 | } 42 | 43 | public function testGetInstalledPlugins_ReturnsStdClassArray() 44 | { 45 | $this->phpciSetup(); 46 | $plugins = $this->testedInformation->getInstalledPlugins(); 47 | $this->assertInternalType("array", $plugins); 48 | $this->assertContainsOnly("stdClass", $plugins); 49 | } 50 | 51 | public function testGetPluginClasses_ReturnsStringArray() 52 | { 53 | $this->phpciSetup(); 54 | $classes = $this->testedInformation->getPluginClasses(); 55 | $this->assertInternalType("array", $classes); 56 | $this->assertContainsOnly("string", $classes); 57 | } 58 | } 59 | 60 | -------------------------------------------------------------------------------- /Tests/PHPCI/Plugin/Util/ExamplePluginConfig.php: -------------------------------------------------------------------------------- 1 | registerResource( 13 | // This function will be called when the resource is needed. 14 | function() { 15 | return array( 16 | 'bar' => "Hello", 17 | ); 18 | }, 19 | "requiredArgument", 20 | null 21 | ); 22 | }; 23 | -------------------------------------------------------------------------------- /Tests/PHPCI/Plugin/Util/Fake/ExamplePluginFull.php: -------------------------------------------------------------------------------- 1 | Options = $options; 30 | } 31 | 32 | public function execute() 33 | { 34 | 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Tests/PHPCI/Plugin/Util/Fake/ExamplePluginWithNoConstructorArgs.php: -------------------------------------------------------------------------------- 1 | RequiredArgument = $requiredArgument; 23 | } 24 | 25 | public function execute() 26 | { 27 | 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Tests/PHPCI/Plugin/Util/Fake/ExamplePluginWithSingleTypedRequiredArg.php: -------------------------------------------------------------------------------- 1 | RequiredArgument = $requiredArgument; 23 | } 24 | 25 | public function execute() 26 | { 27 | 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Tests/PHPCI/Plugin/Util/FilesPluginInformationTest.php: -------------------------------------------------------------------------------- 1 | getInstalledPlugins(); 23 | $this->assertContainsOnlyInstancesOf('stdClass', $pluginInfos); 24 | } 25 | 26 | public function testGetPluginClasses_returnsStrings() 27 | { 28 | $pluginDirPath = realpath(__DIR__ . "/../../../../PHPCI/Plugin/"); 29 | $test = FilesPluginInformation::newFromDir($pluginDirPath); 30 | $pluginInfos = $test->getPluginClasses(); 31 | $this->assertContainsOnly('string', $pluginInfos); 32 | } 33 | } 34 | 35 | -------------------------------------------------------------------------------- /Tests/PHPCI/ProcessControl/PosixProcessControlTest.php: -------------------------------------------------------------------------------- 1 | object = new PosixProcessControl(); 11 | } 12 | 13 | public function testIsAvailable() 14 | { 15 | $this->assertEquals(function_exists('posix_kill'), PosixProcessControl::isAvailable()); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Tests/PHPCI/ProcessControl/UnixProcessControlTest.php: -------------------------------------------------------------------------------- 1 | object = new UnixProcessControl(); 11 | } 12 | 13 | public function getTestCommand() 14 | { 15 | return "read SOMETHING"; 16 | } 17 | 18 | public function testIsAvailable() 19 | { 20 | $this->assertEquals(DIRECTORY_SEPARATOR === '/', UnixProcessControl::isAvailable()); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Tests/PHPCI/ProcessControl/WindowsProcessControlTest.php: -------------------------------------------------------------------------------- 1 | object = new WindowsProcessControl; 11 | } 12 | 13 | public function getTestCommand() 14 | { 15 | return "pause"; 16 | } 17 | 18 | public function testIsAvailable() 19 | { 20 | $this->assertEquals(DIRECTORY_SEPARATOR === '\\', WindowsProcessControl::isAvailable()); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | loadYaml($configFile); 38 | } 39 | 40 | require_once(dirname(__DIR__) . '/vars.php'); 41 | 42 | \PHPCI\Helper\Lang::init($config); 43 | \PHPCI\Helper\Lang::setLanguage("en"); 44 | -------------------------------------------------------------------------------- /Tests/temp/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | # PHPCI Changelog 2 | 3 | ## v.Next 4 | 5 | ### New Features: 6 | - SSH-based Mercurial clones (Commit: [e98647bd](https://github.com/Block8/PHPCI/commit/e98647bd97d49741242d252514b8703504a62869), PR: [#812](https://github.com/Block8/PHPCI/pull/812)) 7 | - Ability to archive projects (Commit: [1466ad06](https://github.com/Block8/PHPCI/commit/1466ad06ef708cbab2b53112fc59e8c1d70c2e33), PR: [#771](https://github.com/Block8/PHPCI/pull/771)) 8 | 9 | ### Bug Fixes and Tweaks: 10 | 11 | -------------------------------------------------------------------------------- /console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | add(new RunCommand($loggerConfig->getFor('RunCommand'))); 33 | $application->add(new RebuildCommand($loggerConfig->getFor('RunCommand'))); 34 | $application->add(new InstallCommand); 35 | $application->add(new UpdateCommand($loggerConfig->getFor('UpdateCommand'))); 36 | $application->add(new GenerateCommand); 37 | $application->add(new DaemonCommand($loggerConfig->getFor('DaemonCommand'))); 38 | $application->add(new PollCommand($loggerConfig->getFor('PollCommand'))); 39 | $application->add(new CreateAdminCommand(Factory::getStore('User'))); 40 | $application->add(new CreateBuildCommand(Factory::getStore('Project'), new BuildService(Factory::getStore('Build')))); 41 | $application->add(new WorkerCommand($loggerConfig->getFor('WorkerCommand'))); 42 | $application->add(new RebuildQueueCommand($loggerConfig->getFor('RebuildQueueCommand'))); 43 | 44 | $application->run(); 45 | -------------------------------------------------------------------------------- /console.bat: -------------------------------------------------------------------------------- 1 | @php console %* -------------------------------------------------------------------------------- /daemon/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /daemonise: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | add(new DaemoniseCommand($loggerConfig->getFor('DaemoniseCommand'))); 20 | $application->run(); 21 | -------------------------------------------------------------------------------- /docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | web: 4 | image: nginx:latest 5 | ports: 6 | - "80:80" 7 | volumes: 8 | - ./public/assets:/phpci/public/assets 9 | - ./public/favicon.ico:/phpci/public/favicon.ico 10 | - ./public/robots.txt:/phpci/public/robots.txt 11 | - ./docker/nginx.conf:/etc/nginx/conf.d/phpci.conf 12 | links: 13 | - fpm 14 | 15 | worker: 16 | image: phpci-worker 17 | build: 18 | context: . 19 | dockerfile: docker/worker.dockerfile 20 | links: 21 | - beanstalkd 22 | volumes: 23 | - .:/phpci 24 | 25 | fpm: 26 | image: phpci-fpm 27 | build: 28 | context: . 29 | dockerfile: docker/fpm.dockerfile 30 | links: 31 | - beanstalkd 32 | volumes: 33 | - .:/phpci 34 | 35 | beanstalkd: 36 | image: schickling/beanstalkd:latest 37 | ports: 38 | - "11300:11300" -------------------------------------------------------------------------------- /docker/fpm-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd /phpci 4 | 5 | # Install composer: 6 | php -r "readfile('https://getcomposer.org/installer');" | php \ 7 | && mv composer.phar /usr/local/bin/composer 8 | 9 | # Install composer dependencies: 10 | composer install -o --no-dev 11 | 12 | # Install npm dependencies: 13 | npm install --production 14 | 15 | mkdir -p /phpci/public/assets/js/AdminLTE 16 | mkdir -p /phpci/public/assets/css 17 | mkdir -p /phpci/public/assets/plugins 18 | 19 | cp -f /phpci/node_modules/admin-lte/dist/js/adminlte.min.js /phpci/public/assets/js/AdminLTE/app.min.js 20 | cp -f /phpci/node_modules/admin-lte/dist/js/pages/dashboard.js /phpci/public/assets/js/AdminLTE/dashboard.js 21 | cp -f /phpci/node_modules/admin-lte/dist/js/demo.js /phpci/public/assets/js/AdminLTE/demo.js 22 | cp -Rf /phpci/node_modules/admin-lte/dist/css/AdminLTE.min.css /phpci/public/assets/css/AdminLTE.min.css 23 | cp -Rf /phpci/node_modules/admin-lte/dist/css/skins/_all-skins.min.css /phpci/public/assets/css/AdminLTE-skins.min.css 24 | cp -Rf /phpci/node_modules/admin-lte/dist/img /phpci/public/assets/ 25 | cp -Rf /phpci/node_modules/admin-lte/plugins /phpci/public/assets/ 26 | cp -f /phpci/node_modules/bootstrap/dist/js/bootstrap.min.js /phpci/public/assets/js/bootstrap.min.js 27 | cp -f /phpci/node_modules/moment/min/moment.min.js /phpci/public/assets/js/moment.min.js 28 | cp -f /phpci/node_modules/sprintf-js/dist/sprintf.min.js /phpci/public/assets/js/sprintf.js 29 | 30 | php-fpm 31 | -------------------------------------------------------------------------------- /docker/fpm.dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:7-fpm 2 | RUN apt update && apt install -qy libcurl3-dev curl gnupg 3 | RUN curl -sL https://deb.nodesource.com/setup_11.x | bash - 4 | RUN apt update && apt install -qy nodejs 5 | RUN docker-php-ext-install -j$(nproc) pdo_mysql 6 | RUN docker-php-ext-install -j$(nproc) curl 7 | 8 | COPY docker/fpm-entrypoint.sh /fpm-entrypoint.sh 9 | 10 | ENTRYPOINT ["/bin/bash", "/fpm-entrypoint.sh"] 11 | -------------------------------------------------------------------------------- /docker/nginx.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80 default_server; 3 | 4 | root /phpci/public; 5 | 6 | location / { 7 | try_files $uri @phpci; 8 | } 9 | 10 | location @phpci { 11 | fastcgi_pass fpm:9000; 12 | fastcgi_index index.php; 13 | fastcgi_buffers 256 4k; 14 | include fastcgi_params; 15 | 16 | fastcgi_param SCRIPT_FILENAME /phpci/public/index.php; 17 | fastcgi_param REQUEST_URI $uri; 18 | fastcgi_param PATH_INFO $uri; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /docker/worker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd /phpci 4 | 5 | # Install composer: 6 | php -r "readfile('https://getcomposer.org/installer');" | php \ 7 | && mv composer.phar /usr/local/bin/composer 8 | 9 | # Install composer dependencies: 10 | composer install -o --no-dev 11 | 12 | php /phpci/console phpci:worker 13 | -------------------------------------------------------------------------------- /docker/worker.dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:7 2 | RUN apt update && apt install -qy git-core libcurl3-dev curl 3 | RUN docker-php-ext-install -j$(nproc) pdo_mysql 4 | RUN docker-php-ext-install -j$(nproc) curl 5 | 6 | RUN git config --global user.name "PHPCI" \ 7 | && git config --global user.email "hello@phptesting.org" 8 | 9 | COPY docker/worker-entrypoint.sh /worker-entrypoint.sh 10 | 11 | ENTRYPOINT ["/bin/bash", "/worker-entrypoint.sh"] 12 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SOURCEDIR = source 8 | BUILDDIR = build 9 | 10 | # Put it first so that "make" without argument is like "make help". 11 | help: 12 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 13 | 14 | .PHONY: help Makefile 15 | 16 | # Catch-all target: route all unknown targets to Sphinx using the new 17 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 18 | %: Makefile 19 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /docs/source/adding-phpci-support-to-your-projects.md: -------------------------------------------------------------------------------- 1 | # Add PHPCI Support to Your Projects 2 | 3 | Similar to Travis CI, to support PHPCI in your project, you simply need to add a `phpci.yml` file to the root of your repository. The file should look something like this: 4 | 5 | ```yml 6 | build_settings: 7 | clone_depth: 1 # depth of 1 is a shallow clone, remove this line to clone entire repo 8 | ignore: 9 | - "vendor" 10 | - "tests" 11 | mysql: 12 | host: "localhost" 13 | user: "root" 14 | pass: "" 15 | 16 | setup: 17 | mysql: 18 | - "DROP DATABASE IF EXISTS test;" 19 | - "CREATE DATABASE test;" 20 | - "GRANT ALL PRIVILEGES ON test.* TO test@'localhost' IDENTIFIED BY 'test';" 21 | composer: 22 | action: "install" 23 | 24 | test: 25 | php_unit: 26 | config: 27 | - "PHPUnit-all.xml" 28 | - "PHPUnit-ubuntu-fix.xml" 29 | directory: 30 | - "tests/" 31 | run_from: "phpunit/" 32 | coverage: "tests/logs/coverage" 33 | php_mess_detector: 34 | allow_failures: true 35 | php_code_sniffer: 36 | standard: "PSR2" 37 | php_cpd: 38 | allow_failures: true 39 | grunt: 40 | task: "build" 41 | 42 | complete: 43 | mysql: 44 | host: "localhost" 45 | user: "root" 46 | pass: "" 47 | - "DROP DATABASE IF EXISTS test;" 48 | ``` 49 | 50 | As mentioned earlier, PHPCI is powered by plugins, there are several phases in which plugins can be run: 51 | 52 | * `setup` - This phase is designed to initialize the build procedure. 53 | * `test` - The tests that should be run during the build. Plugins run during this phase will contribute to the success or failure of the build. 54 | * `complete` - Always called when the `test` phase completes, regardless of success or failure. **Note** that is you do any mysql stuff here, you will need to add the mysql credentials to this section as well, as it runs in a separate instance. 55 | * `success` - Called upon success of the `test` phase. 56 | * `failure` - Called upon failure of the `test` phase. 57 | * `fixed` - Called upon success of the `test` phase if the previous build of the branch was a failure. 58 | * `broken` - Called upon failure of the `test` phase if the previous build of the branch was a success. 59 | 60 | The `ignore` section is merely an array of paths that should be ignored in all tests (where possible.) -------------------------------------------------------------------------------- /docs/source/atoum-plugin.md: -------------------------------------------------------------------------------- 1 | Allows you to run [Atoum](https://github.com/atoum/atoum) unit tests. 2 | 3 | ## Configuration 4 | ### Options 5 | 6 | - **args** [string, optional] - Allows you to pass command line arguments to Atoum. 7 | - **config** [string, optional] - Path to an Atoum configuration file. 8 | - **directory** [string, optional] - Path in which to run Atom (defaults to the build root). 9 | - **executable** [string, optional] - Allows you to provide a path to the Atom binary (defaults to PHPCI root, vendor/bin, or a system-provided Atom binary). 10 | 11 | ### Example 12 | ```yml 13 | test: 14 | atoum: 15 | args: "command line arguments go here" 16 | config: "path to config file" 17 | directory: "directory to run tests" 18 | executable: "path to atoum executable" 19 | ``` 20 | -------------------------------------------------------------------------------- /docs/source/autobuilding from atlassian stash.md: -------------------------------------------------------------------------------- 1 | It is possible to use Stashes External Post Receive Hooks. 2 | Create a post_receive.sh script with execution rights. 3 | Have the EPRH execute the shell script with a positional parameter of your PHPCI build id. 4 | 5 | PROJECT_ID=$1 6 | PHPCI_URL="http://ci.site.com" 7 | while read from_ref to_ref ref_name; do 8 | BRANCH=$(git rev-parse --symbolic --abbrev-ref $ref_name) 9 | echo "Sending webhook" 10 | curl "$PHPCI_URL/webhook/git/$PROJECT_ID?branch=$BRANCH&commit=$to_ref" 11 | done 12 | 13 | Optional, here is a way to send the stash user e-mail and the first 50 characters of the commit message. 14 | ``` 15 | #!/bin/bash 16 | PROJECT_ID=$1 17 | PHPCI_URL="http://ci.site.com" 18 | while read from_ref to_ref ref_name; do 19 | BRANCH=$(git rev-parse --symbolic --abbrev-ref $ref_name) 20 | COMMITMESSAGE=$(git log -n 1 --pretty=format:%s $to_ref | cut -c1-50) 21 | curl -G \ 22 | "$PHPCI_URL/webhook/git/$PROJECT_ID" \ 23 | --data branch=$BRANCH \ 24 | --data commit=$to_ref \ 25 | --data committer=$STASH_USER_EMAIL \ 26 | --data-urlencode message="$COMMITMESSAGE" 27 | done 28 | ``` -------------------------------------------------------------------------------- /docs/source/autobuilding from git by cron.md: -------------------------------------------------------------------------------- 1 | **Example 1:** 2 | 3 | `curl --data "branch=&commit=" http://phpci.example.com/webhook/git/` 4 | 5 | **Example 2:** 6 | 7 | `curl http://phpci.example.com/webhook/git/` 8 | 9 | The default branch is the master branch. 10 | 11 | You can create a cron with one of the commands above: 12 | 13 | `0 1 * * * /usr/bin/curl http://phpci.example.com/webhook/git/` -------------------------------------------------------------------------------- /docs/source/autobuilding-from-bitbucket.md: -------------------------------------------------------------------------------- 1 | # Bitbucket Webhooks 2 | 3 | If you would like your builds to run automatically whenever there is a commit or other similar activity in your Bitbucket repository, perform the following steps: 4 | 5 | 1. Log into PHPCI. 6 | 2. Click on your Bitbucket project. 7 | 3. Copy the web hook link specified on the left. 8 | 4. Log into Bitbucket and go to your repo. 9 | 5. Click the settings cog icon at the top right of the page. 10 | 6. Click on "Hooks" in the left hand menu 11 | 7. Select "POST" from the drop-down and click "Add hook" 12 | 8. Paste the web hook link you copied above, and press save. 13 | -------------------------------------------------------------------------------- /docs/source/autobuilding-from-git.md: -------------------------------------------------------------------------------- 1 | # Git Post Commit Hook 2 | 3 | ## Requirements 4 | - A git repository on a server (bare or plain does not matter) 5 | - [curl](http://curl.haxx.se) to send the web hook 6 | 7 | ## Installation 8 | 1. Create a new file `post-receive` inside the [git `hooks` directory](http://www.git-scm.com/book/en/Customizing-Git-Git-Hooks) with the following content: 9 | 10 | ```shell 11 | #!/bin/sh 12 | 13 | PROJECT_ID=1 14 | PHPCI_URL="http://my.server.com/PHPCI/" 15 | 16 | trigger_hook() { 17 | NEWREV="$2" 18 | REFNAME="$3" 19 | 20 | if [ "$NEWREV" = "0000000000000000000000000000000000000000" ]; then 21 | # Ignore deletion 22 | return 23 | fi 24 | 25 | case "$REFNAME" in 26 | # Triggers only on branches and tags 27 | refs/heads/*|refs/tags/*) ;; 28 | # Bail out on other references 29 | *) return ;; 30 | esac 31 | 32 | BRANCH=$(git rev-parse --symbolic --abbrev-ref "$REFNAME") 33 | COMMITTER=$(git log -1 "$NEWREV" --pretty=format:%ce) 34 | MESSAGE=$(git log -1 "$NEWREV" --pretty=format:%s) 35 | 36 | echo "Sending webhook" 37 | curl \ 38 | --data-urlencode branch="$BRANCH" \ 39 | --data-urlencode commit="$NEWREV" \ 40 | --data-urlencode committer="$COMMITTER" \ 41 | --data-urlencode message="$MESSAGE" \ 42 | "$PHPCI_URL/webhook/git/$PROJECT_ID" 43 | } 44 | 45 | if [ -n "$1" -a -n "$2" -a -n "$3" ]; then 46 | PAGER= trigger_hook $1 $2 $3 47 | else 48 | while read oldrev newrev refname; do 49 | trigger_hook $oldrev $newrev $refname 50 | done 51 | fi 52 | ``` 53 | 54 | 2. Change the file to be executable: `chmod a+x post-receive` 55 | 3. Push changes to the repository -------------------------------------------------------------------------------- /docs/source/autobuilding-from-github.md: -------------------------------------------------------------------------------- 1 | # Github Webhooks 2 | 3 | If you would like your builds to run automatically whenever there is a commit or other similar activity in your GitHub repository, perform the following steps: 4 | 5 | 1. Log into PHPCI. 6 | 2. Click on your GitHub project. 7 | 3. Copy the web hook link specified on the right of the page. 8 | 4. Log into GitHub and go to your repository. 9 | 5. Click the settings icon on the lower right sidebar. 10 | 6. Click on "Webhooks & Services". 11 | 7. Add your web hook link you copied above, and specify when you would like it to run. 12 | 8. Add the public key for the project in PHPCI to the deploy keys for the repository on GitHub. 13 | 9. Verify that the initial test delivery was successful. If not, make sure that your PHPCI machine is reachable from the internet. -------------------------------------------------------------------------------- /docs/source/autobuilding-from-gitlab.md: -------------------------------------------------------------------------------- 1 | # Gitlab Webhooks 2 | 3 | If you would like your builds to run automatically whenever there is a commit or other similar activity in your Gitlab repository, perform the following steps: 4 | 5 | 1. Log into PHPCI. 6 | 2. Click on your Gitlab project. 7 | 3. Copy the web hook link specified on the right. 8 | 4. Log into Gitlab and go to your repo. 9 | 5. Click the "settings" tab in the top right corner of the page. 10 | 6. Click on "Web Hooks". 11 | 7. Paste the link you copied from PHPCI into the "URL" textbox. 12 | 8. Select the events which you want to trigger a PHPCI build. The default and recommended setup is to only enable "push events." 13 | 9. Click "Add Web Hook," and verify that the test was successful. -------------------------------------------------------------------------------- /docs/source/behat-plugin.md: -------------------------------------------------------------------------------- 1 | A very simple plugin for running [Behat](http://behat.org/) BDD tests. 2 | 3 | ## Configuration 4 | ### Options 5 | - **executable** [string, optional] - Allows you to provide a path to the Behat binary (defaults to PHPCI root, vendor/bin, or a system-provided Behat binary). 6 | - **features** [string, optional] - Provide a list of Behat features to run. 7 | 8 | ### Example 9 | ```yml 10 | test: 11 | behat: 12 | executable: "path to behat binary" 13 | features: "command line arguments" 14 | ``` 15 | -------------------------------------------------------------------------------- /docs/source/branch-specific-stages.md: -------------------------------------------------------------------------------- 1 | PHPCI allows you configure plugins depending on the branch you configure in the project settings in the UI. You can replace a complete stage for a branch, or add extra plugins to a stage that run before or after the default plugins. 2 | 3 | # Example config 4 | test: # Test stage config for all branches 5 | php_unit: 6 | allow_failures: 10 7 | success: # Success stage config for all branches 8 | shell: ./notify 9 | branch-release: # Test config for release branch 10 | run-option: replace # This can be set to either before, after or replace 11 | test: 12 | php_unit: 13 | allow_failures: 0 14 | branch-master: # Test config for release branch 15 | run-option: after # This can be set to either before, after or replace 16 | success: 17 | shell: 18 | - "rsync ..." 19 | 20 | # How it works 21 | When you have configured a branch eg "stable" in the project settings in the UI. Add a new config named "branch-BRANCH NAME", in this case "branch-stable" to the phpci.yml. In this config, specify all stages and plugins you wish to run. 22 | 23 | Also add a new config value "run-option", that can heve 3 values: 24 | * before: will cause the branch specific plugins to run before the default ones 25 | * after: will cause the branch specific plugins to run after the default ones 26 | * replace: will cause the branch specific plugins to run and the default ones not 27 | 28 | # References 29 | * https://github.com/Block8/PHPCI/issues/1045 30 | * https://github.com/Block8/PHPCI/issues/1209 31 | * https://github.com/Block8/PHPCI/blob/master/PHPCI/Plugin/Util/Executor.php -------------------------------------------------------------------------------- /docs/source/campfire-plugin.md: -------------------------------------------------------------------------------- 1 | This plugin joins a [Campfire](https://campfirenow.com/) room and sends a user-defined message, for example a "Build Succeeded" message. 2 | 3 | ## Configuration 4 | ### Options 5 | - **authToken** [string, required] - Your Campfire user authentication token. 6 | - **message** [string, required] - The message to send to the room. 7 | - **roomId** [string, required] - Your Campfire room ID number. 8 | - **url** [string, required] - Your Campfire chat room URL. 9 | 10 | ### Example 11 | ```yml 12 | build_settings: 13 | campfire: 14 | authToken: "campfire auth token" 15 | roomId: "campfire room ID" 16 | url: "campfire URL" 17 | success: 18 | campfire: 19 | message: "Build succeeded!" 20 | ``` 21 | -------------------------------------------------------------------------------- /docs/source/clean-build-plugin.md: -------------------------------------------------------------------------------- 1 | Works through a list of files to remove from your build. Useful when used in combination with Copy Build or Package Build. 2 | 3 | ### Configuration Options: 4 | 5 | * **remove** - Required - An array of files and / or directories to remove. 6 | 7 | ### Example Configuration: 8 | 9 | ```yml 10 | complete: 11 | clean_build: 12 | remove: 13 | - composer.json 14 | - composer.phar 15 | - config.dev.php 16 | ``` -------------------------------------------------------------------------------- /docs/source/codeception-plugin.md: -------------------------------------------------------------------------------- 1 | A simple plugin that allows you to run [Codeception](http://codeception.com/) tests. 2 | 3 | ### Configuration Options: 4 | 5 | * **config** - Required - Can be either a single string pointing to a Codeception configuration file, or an array of configuration file paths. By default this is called `codeception.yml` and will be in the root of your project. 6 | 7 | * **args** - Optional - The string of arguments to be passed to the run command. **Important**, due to the assumption made on line [132](https://github.com/Block8/PHPCI/blob/master/PHPCI/Plugin/Codeception.php#L132) regarding the value of `--xml` being the next argument which will not be correct if the user provides arguments using this config param, you must specify `report.xml` before any user input arguments to satisfy the report processing on line [146](https://github.com/Block8/PHPCI/blob/master/PHPCI/Plugin/Codeception.php#L146) 8 | 9 | * **path** - Optional - The path from the root of your project to the root of the codeception _output directory 10 | 11 | ##### Default values 12 | 13 | - config 14 | - `codeception.yml` if it exists in the root of the project 15 | - `codeception.dist.yml` if it exists in the root of the project 16 | - null if no option provided and the above two fail, this will cause an Exception to be thrown on execution 17 | 18 | - args 19 | - Empty string 20 | 21 | - path 22 | - `tests/_output/` 23 | 24 | ##### Example on running codeception with default settings (when tests are in tests/ directory): 25 | 26 | ``` 27 | codeception: 28 | config: "codeception.yml" 29 | path: "tests/" 30 | ``` 31 | 32 | ##### Example usage against the Yii2 framework 33 | 34 | ``` 35 | codeception: 36 | allow_failures: false 37 | config: "tests/codeception.yml" 38 | path: "tests/codeception/_output/" 39 | args: "report.xml --no-ansi --coverage-html" 40 | ``` 41 | 42 | The path value will need to be changed if you have your tests directory somewhere other than in the root of the project. -------------------------------------------------------------------------------- /docs/source/composer-plugin.md: -------------------------------------------------------------------------------- 1 | Allows you to run Composer within your build, to install dependencies prior to testing. Best run as a "setup" stage plugin. 2 | 3 | ## Configuration 4 | ### Options 5 | * **directory** [optional, string] - Directory within which you want Composer to run (default: build root) 6 | * **action** [optional, string, update|install] - Action you wish Composer to run (default: 'install') 7 | * **prefer_dist** [optional, bool, true|false] - whether Composer should run with the `--prefer-dist` flag (default: false) 8 | 9 | ### Example 10 | ```yml 11 | setup: 12 | composer: 13 | directory: "my/composer/dir" 14 | action: "update" 15 | prefer_dist: true 16 | ``` 17 | 18 | ## Warning 19 | 20 | If you are using a Composer private repository like Satis, with HTTP authentication, you must check your username and password inside the ```auth.json``` file. PHPCI uses the ```--no-interaction``` flag, so it will not warn if you must provide that info. 21 | 22 | For more info, please check the Composer documentation. 23 | 24 | https://getcomposer.org/doc/04-schema.md#config -------------------------------------------------------------------------------- /docs/source/configuring-phpci.md: -------------------------------------------------------------------------------- 1 | # Configuring PHPCI 2 | 3 | The PHPCI configuration on the server is automatically generated into the `phpci/PHPCI/config.yml` file during installation. One might need to also edit the file manually. 4 | 5 | For example, to [disable authentication](https://www.phptesting.org/news/phpci-1-5-released), one could log into phpci and go into the settings to disable it. But if you have already set up a username/password pair and have forgotten the password, and if the server is on a local network, and it's not sending the `forgot password` email, then editing the config file manually would be handy. To do so, just edit the `phpci` section in the config file (which is in [yaml format](https://en.wikipedia.org/wiki/YAML)), and add 6 | 7 | phpci: 8 | authentication_settings: 9 | state: 1 10 | user_id: 1 11 | 12 | where you can get the user_id by logging into the mysql database and selecting your user ID from the `users` table in the `phpci` database. -------------------------------------------------------------------------------- /docs/source/contributing-to-phpci.md: -------------------------------------------------------------------------------- 1 | Please find the updated contributing guidelines here: https://github.com/Block8/PHPCI/blob/master/.github/CONTRIBUTING.md -------------------------------------------------------------------------------- /docs/source/copy-build-plugin.md: -------------------------------------------------------------------------------- 1 | Copies all files from your build, with the exception of those in the "ignore" build settings property, to a directory of your choosing. 2 | 3 | ### Configuration Options: 4 | 5 | * **directory** - Required - The directory to which you want to copy the build. 6 | * **respect_ignore** - Optional - Whether to respect the global "ignore" setting when copying files. Default is false. 7 | * **wipe** - Optional - Set true if you want destination directory to be cleared before copying. Default is false. -------------------------------------------------------------------------------- /docs/source/custom-plugins-setup.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | Installing 3rd party plugins is straight forward and handled through composer. In the root folder of your phpci instance update the ```composer.json``` file to include the new plugins you require: 4 | 5 | ```yaml 6 | "require": { 7 | \\... 8 | "meadsteve/example-phpci-plugin" : "dev-master", 9 | \\... 10 | } 11 | ``` 12 | running ```composer update plugin-provider/plugin-package ``` will then download the plugin. 13 | 14 | # Usage 15 | 16 | Once a new plugin has been installed to phpci any project can make use of this plugin. The plugin is referenced in the ```phpci.yml``` as a full class name including namespaces: 17 | 18 | ```yml 19 | setup: 20 | test: 21 | php_mess_detector: 22 | allowed_warnings: 0 23 | \meadsteve\PhpciPlugins\ExamplePlugin: 24 | option_one: 2 25 | ``` 26 | 27 | # Extra dependency configuration 28 | //TODO: document ```pluginconfig.php``` in project root. -------------------------------------------------------------------------------- /docs/source/deployer.md: -------------------------------------------------------------------------------- 1 | Triggers a deployment of the project to run via [Deployer](http://phpdeployment.org) 2 | 3 | **Configuration Options:** 4 | ### Options 5 | * **webhook_url** [required, string] - The URL to your Deployer WebHook 6 | * **reason** [optional, string] - Your deployment message. Default - PHPCI Build #%BUILD% - %COMMIT_MESSAGE% 7 | * **update_only** [optional, bool, true|false] - Whether the deployment should only be run if the currently deployed branches matches the one being built. Default - true 8 | 9 | ### Example 10 | ```yaml 11 | success: 12 | deployer: 13 | webhook_url: "https://deployer.example.com/deploy/QZaF1bMIUqbMFTmKDmgytUuykRN0cjCgW9SooTnwkIGETAYhDTTYoR8C431t" 14 | reason: "PHPCI Build #%BUILD% - %COMMIT_MESSAGE%" 15 | update_only: true 16 | ``` -------------------------------------------------------------------------------- /docs/source/email-plugin.md: -------------------------------------------------------------------------------- 1 | Sends a build status email. 2 | 3 | ### Configuration Options: 4 | 5 | * **committer** - Whether or not to send the email to the committer that prompted this build. 6 | * **addresses** - A list of addresses to send to. 7 | * **default_mailto_address** - A default address to send to. 8 | * **cc** - A list of addresses that will receive a copy of every emails sent. 9 | * **template** - The template to use, options are short and long. Default is short on success and long otherwise. 10 | 11 | 12 | **Note:** _This plugin will only work if you configured email settings during installation or configured them later in Admin Options > Settings > Email Settings_ 13 | 14 | ### Configuration Example 15 | See [Adding PHPCI Support to Your Projects](https://www.phptesting.org/wiki/Adding-PHPCI-Support-to-Your-Projects) for more information about how to configure plugins. 16 | 17 | Send an email to the committer as well as one@exameple.com if a build fails: 18 | ```yml 19 | failure: 20 | email: 21 | committer: true 22 | default_mailto_address: one@example.com 23 | ``` 24 | 25 | Send an email to one@example.com every time a build is run: 26 | ```yml 27 | complete: 28 | email: 29 | default_mailto_address: one@example.com 30 | ``` -------------------------------------------------------------------------------- /docs/source/env-plugin.md: -------------------------------------------------------------------------------- 1 | Sets environment variables on the PHPCI server for the build. 2 | 3 | ### Sample Configuration: 4 | 5 | ```yml 6 | setup: 7 | env: 8 | APPLICATION_ENV: "development" 9 | ``` -------------------------------------------------------------------------------- /docs/source/example-phpci.yml.md: -------------------------------------------------------------------------------- 1 | These are just some example yaml config files 2 | 3 | ``` 4 | build_settings: 5 | verbose: false 6 | prefer_symlink: false 7 | 8 | setup: 9 | 10 | test: 11 | php_unit: 12 | directory: "test/phpunit/" 13 | args: "--bootstrap 'test/phpunit/bootstrap.php' --configuration 'test/phpunit/phpunit.xml'" 14 | 15 | complete: 16 | ``` -------------------------------------------------------------------------------- /docs/source/grunt-plugin.md: -------------------------------------------------------------------------------- 1 | This plugin runs [Grunt](http://gruntjs.com/) tasks. 2 | 3 | ## Configuration 4 | ### Options 5 | - **directory** [string, optional] - The directory in which to run Grunt (defaults to build root.) 6 | - **grunt** [string, optional] - Allows you to provide a path to Grunt (defaults to PHPCI root, vendor/bin, or a system-provided Grunt). 7 | - **gruntfile** [string, optional] - Gruntfile to run (defaults to `Gruntfile.js`). 8 | - **task** [string, optional] - The Grunt task to run. 9 | 10 | ### Example 11 | ```yml 12 | test: 13 | grunt: 14 | directory: "path to run grunt in" 15 | grunt: "path to grunt executable" 16 | gruntfile: "gruntfile.js" 17 | task: "css" 18 | ``` 19 | -------------------------------------------------------------------------------- /docs/source/hipchat-notify-plugin.md: -------------------------------------------------------------------------------- 1 | This plugin joins a [HipChat](https://www.hipchat.com/) room and sends a user-defined message, for example a "Build Succeeded" message. 2 | 3 | **Configuration Options:** 4 | 5 | | Field | Required? | Description | 6 | |-------|-----------|-------------| 7 | | `authToken` | Yes | Your HipChat API authentication token (v1) | 8 | | `room` | Yes | Your Hipchat room name or ID number. This can also be an array of room names or numbers, and the message will be sent to all rooms. | 9 | | `message` | No | The message to send to the room. Default - `%PROJECT_TITLE% built at %BUILD_URI%` | 10 | | `color` | No | Message color. Valid values: yellow, green, red, purple, gray, random. Default - `yellow`| 11 | | `notify` | No | Whether or not this message should trigger a notification for people in the room (change the tab color, play a sound, etc). Default - `false`. | 12 | 13 | Message can be formatted via HTML. Example: 14 | ```html 15 | %PROJECT_TITLE% - build %BUILD% failed! 16 | ``` 17 | 18 | Configuration example: 19 | ```yaml 20 | hipchat_notify: 21 | authToken: 123 22 | room: 456 23 | message: %PROJECT_TITLE% - build %BUILD% failed! 24 | color: red 25 | notify: true 26 | ``` 27 | -------------------------------------------------------------------------------- /docs/source/installing-phpci.md: -------------------------------------------------------------------------------- 1 | # Installing PHPCI 2 | 3 | ## What you'll need 4 | 5 | * PHP 5.3.6 or above 6 | * A web server (we recommend [nginx](http://nginx.org)) 7 | * [Composer](https://getcomposer.org/download/) 8 | * [Git](http://git-scm.com/downloads) 9 | * A MySQL server to connect to. This doesn't have to be on the same server as PHPCI. 10 | * The following functions need to be enabled: `exec()`, `shell_exec()` and `proc_open()` 11 | * PHP must have OpenSSL support enabled. 12 | 13 | ## Installing PHPCI from Composer 14 | 15 | * Go to the directory in which you want to install PHPCI, for example: `/var/www` 16 | * Download Composer if you haven't already: `curl -sS https://getcomposer.org/installer | php` 17 | * Download PHPCI: `./composer.phar create-project block8/phpci phpci --keep-vcs --no-dev` 18 | * Go to the newly created PHPCI directory, and install Composer dependencies: `cd phpci && ../composer.phar install` 19 | * Run the PHPCI installer: `php ./console phpci:install` 20 | * [Add a virtual host to your web server](Add-a-Virtual-Host), pointing to the `public` directory within your new PHPCI directory. You'll need to set up rewrite rules to point all non-existent requests to PHPCI. 21 | * [Set up the PHPCI Worker](Run-Builds-Using-a-Worker), or you can run builds using the [PHPCI daemon](Run-Builds-Using-a-Daemon) or [a cron-job](Run-Builds-Using-Cron) to run PHPCI builds. 22 | 23 | ## Installing PHPCI Manually 24 | 25 | * Go to the directory in which you want to install PHPCI, for example: `/var/www` 26 | * [Download PHPCI](https://github.com/Block8/PHPCI/releases/latest) and unzip it. 27 | * Go to the PHPCI directory: `cd /var/www/phpci` 28 | * Install dependencies using Composer: `composer install` 29 | * Install PHPCI itself: `php ./console phpci:install` 30 | * [Add a virtual host to your web server](Add-a-Virtual-Host), pointing to the `public` directory within your new PHPCI directory. You'll need to set up rewrite rules to point all non-existent requests to PHPCI. 31 | * [Set up the PHPCI Worker](Run-Builds-Using-a-Worker), or you can run builds using the [PHPCI daemon](Run-Builds-Using-a-Daemon) or [a cron-job](Run-Builds-Using-Cron) to run PHPCI builds. 32 | 33 | ### Extended Guides 34 | - [Installing PHPCI on Mac OSX Mavericks](Vanilla-Mac-Mavericks-Server-Installation-Guide) 35 | - [Installing PHPCI on Mac OSX Yosemite](Vanilla-Installation-on-OS-X-10.10-Yosemite-with-OS-X-Server-4) -------------------------------------------------------------------------------- /docs/source/interpolation.md: -------------------------------------------------------------------------------- 1 | # Variable Interpolation 2 | 3 | Most strings used in the build configuration can have variables related to the build inserted into them with the following syntax: 4 | 5 | "My important message is about %SOMETHING%" 6 | 7 | Where something can be one of the following: 8 | 9 | 10 | * **COMMIT** - The commit hash 11 | * **SHORT_COMMIT** - The shortened version of the commit hash 12 | * **COMMIT_EMAIL** - The email address of the committer 13 | * **COMMIT_MESSAGE** - The message written by the committer 14 | * **COMMIT_URI** - The URL to the commit 15 | * **BRANCH** - The name of the branch 16 | * **BRANCH_URI** - The URL to the branch 17 | * **PROJECT** - The ID of the project 18 | * **BUILD** - The build number 19 | * **PROJECT_TITLE** - The name of the project 20 | * **BUILD_PATH** - The path to the build 21 | * **BUILD_URI** - The URL to the build in PHPCI -------------------------------------------------------------------------------- /docs/source/irc-plugin.md: -------------------------------------------------------------------------------- 1 | Connects to an IRC server and sends a defined message. 2 | 3 | ### Configuration Options: 4 | 5 | * **message** - Required - The message to send. 6 | 7 | ### Build Settings 8 | 9 | * **irc** - All child properties are required 10 | * **server** - IRC server to connect to. 11 | * **port** - IRC server port, defaults to 6667. 12 | * **room** - The room you wish to send your message to (must start with a #) 13 | * **nick** - The nickname you want the bot to use. -------------------------------------------------------------------------------- /docs/source/lint-plugin.md: -------------------------------------------------------------------------------- 1 | This plugin runs PHP's built in Lint (syntax / error check) functionality. 2 | 3 | ## Configuration 4 | ### Options 5 | - **directory** [string, optional] - A single path in which you wish to lint files. 6 | - **directories** [array, optional] - An array of paths in which you wish to lint files. This overrides `directory`. 7 | - **recursive** [bool, optional] - Whether or not you want to recursively check sub-directories of the above (defaults to true). 8 | 9 | ### Example 10 | ```yml 11 | test: 12 | lint: 13 | directory: "single path to lint files" 14 | directories: 15 | - "directory to lint files" 16 | - "directory to lint files" 17 | - "directory to lint files" 18 | recursive: false 19 | ``` 20 | -------------------------------------------------------------------------------- /docs/source/logging.md: -------------------------------------------------------------------------------- 1 | # Basics 2 | The phpci codebase makes use of the [psr3](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md) logging standard. By default we use [Monolog](https://github.com/Seldaek/monolog) to handle the actual work implementing this standard. 3 | 4 | # How to Setup Logging (For people running a PHPCI instance) 5 | The only step required to activate logging is to create a file in the root directory called loggerconfig.php with content like the following: 6 | 7 | ```php 8 | function () { 12 | return array( 13 | new \Monolog\Handler\StreamHandler('path/to/log', \Monolog\Logger::ERROR), 14 | ); 15 | } 16 | ); 17 | ``` 18 | This file should return an array of key value pairs. Each key tells phpci which command to attach the logger to (the underscore is a special value which matches all commands). For each command an array of [Monolog](https://github.com/Seldaek/monolog) handlers should be returned. In the example above we've used one that simply writes to the file system but in practise this could be any handler written for monolog. 19 | 20 | Once this file is created all plugins and core phpci functionality should start writing to the configured handlers. 21 | 22 | # How to write to the Log (For people creating a new plugin) 23 | 24 | ## Using the plugin constructor to get a logger directly 25 | For plugin creators the simplest way to get hold of an error logger is to add a parameter to the constructor and typehint on 'Psr\Log\LoggerInterface'. The code that loads your plugin will automatically inject the logger when it sees this. For example: 26 | ```php 27 | class ExampleLoggingPlugin implements \PHPCI\Plugin 28 | { 29 | protected $log; 30 | 31 | public function __construct(Psr\Log\LoggerInterface $log) 32 | { 33 | $this->log = $log; 34 | } 35 | 36 | public function execute() 37 | { 38 | $this->log->notice("You'll notice this in the log"); 39 | } 40 | } 41 | ``` 42 | 43 | ## Using convenience methods provided by the Builder 44 | Your plugin can also call a couple of messages on the Builder object: 45 | 46 | logSuccess() 47 | logFailure() 48 | log() 49 | 50 | All calls will get piped through to the appropriate logger. 51 | 52 | -------------------------------------------------------------------------------- /docs/source/mysql-plugin.md: -------------------------------------------------------------------------------- 1 | Connects to a given MySQL server and runs a selection of queries. 2 | 3 | ### Example Configuration: 4 | 5 | ```yaml 6 | build_settings: 7 | mysql: 8 | host: 'localhost' 9 | user: 'testuser' 10 | pass: '12345678' 11 | 12 | setup: 13 | mysql: 14 | - "CREATE DATABASE my_app_test;" 15 | 16 | complete: 17 | mysql: 18 | - "DROP DATABASE my_app_test;" 19 | ``` 20 | 21 | Import SQL from file: 22 | ```yaml 23 | setup: 24 | mysql: 25 | import-from-file: # This key name doesn´t matter 26 | import: 27 | database: "foo" # Database name 28 | file: "/path/dump.sql" # Relative path in build folder 29 | ``` -------------------------------------------------------------------------------- /docs/source/package-build-plugin.md: -------------------------------------------------------------------------------- 1 | Builds a tar or zip archive of your build and places it in a directory of your choosing. 2 | 3 | ### Configuration Options: 4 | 5 | * **directory** - Required - Directory in which to put the package file. 6 | * **filename** - Required - File name for the package. 7 | * **format** - Required - `tar` or `zip` 8 | 9 | You can use following variables in filename: 10 | 11 | * %build.commit% 12 | * %build.id% 13 | * %build.branch% 14 | * %project.title% 15 | * %date% 16 | * %time% -------------------------------------------------------------------------------- /docs/source/pdepend-plugin.md: -------------------------------------------------------------------------------- 1 | Runs [PDepend](http://pdepend.org/) software metrics. 2 | 3 | ### Configuration Options: 4 | 5 | * **directory** - Required - Directory in which to run PDepend. -------------------------------------------------------------------------------- /docs/source/phar-plugin.md: -------------------------------------------------------------------------------- 1 | Allows you to create a [Phar](http://php.net/manual/en/book.phar.php) archive from your project. 2 | 3 | ### Example 4 | 5 | ``` 6 | phar: 7 | directory: /path/to/directory 8 | filename: foobar.phar 9 | regexp: /\.(php|phtml)$/ 10 | stub: filestub.php 11 | ``` 12 | 13 | ### Configuration Options 14 | 15 | * **directory**: `phar` output directory. Default: `%buildpath%`; 16 | * **filename**: `phar` filename inside output directory. Default: `build.phar`; 17 | * **regexp**: regular expression for Phar iterator. Default: `/\.php$/`; and 18 | * **stub**: stub content filename. No default value. -------------------------------------------------------------------------------- /docs/source/phing-plugin.md: -------------------------------------------------------------------------------- 1 | This plugin allows you to use the Phing build system to build your project. 2 | 3 | ### Configuration options: 4 | * **directory** - Relative path to the directory in which you want to run phing. 5 | * **build_file** - Your phing build.xml file. 6 | * **targets** - Which build targets you want to run. 7 | * **properties** - Any custom properties you wish to pass to phing. 8 | * **property_file** - A file containing properties you wish to pass to phing. 9 | 10 | ### Sample config: 11 | ```yml 12 | phing: 13 | build_file: 'build.xml' 14 | targets: 15 | - "build:test" 16 | properties: 17 | config_file: "PHPCI" 18 | ``` -------------------------------------------------------------------------------- /docs/source/php-code-sniffer-plugin.md: -------------------------------------------------------------------------------- 1 | Runs PHP Code Sniffer against your build. 2 | 3 | ## Configuration 4 | ### Options 5 | * **allowed_warnings** [int, optional] - The warning limit for a successful build. 6 | * **allowed_errors** [int, optional] - The error limit for a successful build. 7 | * **suffixes** [array, optional] - An array of file extensions to check. 8 | * **standard** [string, optional] - The standard against which your files should be checked (defaults to PSR2.) 9 | * **tab_width** [int, optional] - Your chosen tab width. 10 | * **encoding** [string, optional] - The file encoding you wish to check for. 11 | * **path** [string, optional] - Path in which to run PHP Code Sniffer. 12 | * **ignore** [array, optional] - A list of files / paths to ignore, defaults to the build_settings ignore list. 13 | 14 | ### Example 15 | Simple example where PHPCS will run on app directory, but ignore the views folder, and use PSR-1 and PSR-2 rules for validation: 16 | ```yml 17 | test: 18 | php_code_sniffer: 19 | path: "app" 20 | ignore: 21 | - "app/views" 22 | standard: "PSR1,PSR2" 23 | ``` 24 | 25 | For use with an existing project: 26 | ```yml 27 | test: 28 | php_code_sniffer: 29 | standard: "/phpcs.xml" # The leading slash is needed to trigger an external ruleset. 30 | # Without it, PHPCI looks for a rule named "phpcs.xml" 31 | allowed_errors: -1 # Even a single error will cause the build to fail. -1 = unlimited 32 | allowed_warnings: -1 33 | ``` -------------------------------------------------------------------------------- /docs/source/php-coding-standards-fixer-plugin.md: -------------------------------------------------------------------------------- 1 | Runs PHP Coding Standards Fixer against your build. 2 | 3 | ## Configuration 4 | ### Options 5 | * **verbose** [bool, optional] - Whether to run in verbose mode (default: false) 6 | * **diff** [bool, optional] - Whether to run with the `--diff` flag enabled (default: false) 7 | * **level** [string, optional] - `psr0`, `psr1`, `psr2`, or `symphony` (default: all) 8 | * **workingdir** [string, optional] - The directory in which PHP CS Fixer should work (default: build root) 9 | 10 | ### Example 11 | ```yml 12 | test: 13 | php_cs_fixer: 14 | verbose: true 15 | diff: true 16 | level: "psr2" 17 | workingdir: "my/dir/path" 18 | ``` 19 | 20 | ## Warning 21 | There is currently a bug with this plugin that will cause an error if you leave the level to default to `all`. That level does not exist and will cause the build to fail. Instead specify the level explicitly until this is fixed. -------------------------------------------------------------------------------- /docs/source/php-copy-paste-detector-plugin.md: -------------------------------------------------------------------------------- 1 | Runs PHP Copy / Paste Detector against your build. 2 | 3 | ## Configuration 4 | ### Options 5 | * **path** - Optional - Path in which to run PHP Copy/Paste Detector (default: build root). 6 | * **ignore** - Optional - A list of files / paths to ignore (default: build_settings > ignore). 7 | * **standard** [string, optional] - which PSR standard to follow (default: 'PSR1'). 8 | 9 | ### Example 10 | 11 | ```yml 12 | test: 13 | php_cpd: 14 | standard: "PSR2" 15 | path: "app" 16 | ignore: 17 | - "app/my/path" 18 | ``` 19 | -------------------------------------------------------------------------------- /docs/source/php-docblock-checker.md: -------------------------------------------------------------------------------- 1 | Runs the PHP Docblock Checker against your build. This tool verifies that all classes and methods have docblocks. 2 | 3 | ### Configuration Options: 4 | 5 | * **allowed_warnings** - Optional - The warning limit for a successful build. 6 | * **path** - Optional - Directory in which PHP Docblock Checker should run. 7 | * **skip_methods** - Optional - Tells the checker to ignore methods that don't have a docblock. 8 | * **skip_classes** - Optional - Tells the checker to ignore classes that don't have a docblock. 9 | 10 | ### Example config: 11 | 12 | ```yml 13 | php_docblock_checker: 14 | allowed_warnings: 10 15 | skip_classes: true 16 | ``` -------------------------------------------------------------------------------- /docs/source/php-loc-plugin.md: -------------------------------------------------------------------------------- 1 | Runs [PHPLoc](https://github.com/sebastianbergmann/phploc) against your project and records some key metrics. 2 | 3 | ## Configuration 4 | ### Options 5 | * **directory** - Optional - The directory in which phploc should run. 6 | 7 | ### Example 8 | Run PHPLOC against the app directory only. This will prevent inclusion of code from 3rd party libraries that are included outside of the app directory. 9 | 10 | ```yml 11 | test: 12 | php_loc: 13 | directory: "app" 14 | ``` 15 | -------------------------------------------------------------------------------- /docs/source/php-mess-detector-plugin.md: -------------------------------------------------------------------------------- 1 | Runs PHP Mess Detector against your build. Records some key metrics, and also reports errors and warnings. 2 | 3 | ## Configuration 4 | ### Options 5 | - **allowed_warnings** [int, optional] - The warning limit for a successful build (default: 0). -1 disables warnings. Setting allowed_warnings in conjunction with zero_config will override zero_config. 6 | - **suffixes** [array, optional] - An array of file extensions to check (default: 'php') 7 | - **ignore** [array, optional] - An array of files/paths to ignore (default: build_settings > ignore) 8 | - **path** [string, optional] - Directory in which PHPMD should run (default: build root) 9 | - **rules** [array, optional] - Array of rulesets that PHPMD should use when checking your build or a string containing at least one slash, will be treated as path to PHPMD ruleset. See http://phpmd.org/rules/index.html for complete details on the rules. (default: ['codesize', 'unusedcode', 'naming']). 10 | - **zero_config** [bool, optional] - Suppresses build failure on errors and warnings if set to true. (default: false). 11 | 12 | 13 | ### Example 14 | ```yml 15 | test: 16 | php_mess_detector: 17 | path: 'app' 18 | ignore: 19 | - 'vendor' 20 | allowed_warnings: -1 21 | rules: 22 | - "cleancode" 23 | - "controversial" 24 | - "codesize" 25 | - "design" 26 | - "naming" 27 | - "unusedcode" 28 | - "somedir/customruleset.xml" 29 | zero_config: true 30 | ``` -------------------------------------------------------------------------------- /docs/source/php-parallel-lint-plugin.md: -------------------------------------------------------------------------------- 1 | Similar to the [standard PHP Lint plugin](Lint-plugin), except that it uses the [PHP Parallel Lint](https://github.com/JakubOnderka/PHP-Parallel-Lint) project to run. 2 | 3 | ## Configuration 4 | ### Options 5 | * **directory** [string, optional] - directory to inspect (default: build root) 6 | * **ignore** [array, optional] - directory to ignore (default: inherits ignores specified in setup) 7 | * **extensions** [string, optional] - comma separated list of file extensions of files containing PHP to be checked (default: php) 8 | 9 | ### Example 10 | ```yml 11 | test: 12 | php_parallel_lint: 13 | directory: "app" 14 | ignore: 15 | - "vendor" 16 | - "test" 17 | extensions: php, html 18 | ``` 19 | -------------------------------------------------------------------------------- /docs/source/php-spec-plugin.md: -------------------------------------------------------------------------------- 1 | Runs [PHP Spec](http://www.phpspec.net/) tests against your build. 2 | 3 | ### Configuration Options: 4 | 5 | * **bootstrap** - Optional - Path to a PHPSpec bootstrap file. 6 | 7 | ### Example 8 | 9 | ``` 10 | build_settings: 11 | [...] 12 | 13 | setup: 14 | [...] 15 | 16 | test: 17 | php_spec: 18 | 19 | complete: 20 | [...] 21 | 22 | success: 23 | [...] 24 | ``` -------------------------------------------------------------------------------- /docs/source/phpci-config.md: -------------------------------------------------------------------------------- 1 | **From email address:** 2 | 3 | If you want to change the from email address, where the application send emails from, than you are able to change the configuration in /phpci/PHPCI/config.yml like this: 4 | 5 | b8: 6 | database: { servers: { read: localhost, write: localhost }, name: example, username: example, password: example } 7 | phpci: 8 | url: 'http://phpci.example.com' 9 | email_settings: 10 | from_address: 'phpci@example.com' -------------------------------------------------------------------------------- /docs/source/phpunit-plugin.md: -------------------------------------------------------------------------------- 1 | Runs PHPUnit tests against your build. 2 | ## Configuration 3 | ### Options 4 | Has two modes: 5 | 6 | #### phpunit.xml Configuration File 7 | Its activated if you have phpunit.xml file in your build path, `tests/` subfolder, or you specify it as a parameter: 8 | * **config** - Optional - Path to a PHP Unit XML configuration file. 9 | * **run_from** - Optional - When running PHPUnit with an XML config, the command is run from this directory 10 | * **coverage** - Optional - Value for the `--coverage-html` command line flag. 11 | * **path** - Optional - In cases where tests files are in a sub path of the /tests path, allows this path to be set in the config. 12 | 13 | #### Running Tests By Specifying Directory 14 | * **directory** - Optional - The directory (or array of dirs) to run PHPUnit on 15 | 16 | Both modes accept: 17 | * **args** - Optional - Command line args (in string format) to pass to PHP Unit 18 | 19 | ### Examples 20 | Specify config file and test directory: 21 | ```yml 22 | test: 23 | php_unit: 24 | config: 25 | - "path/to/phpunit.xml" 26 | path: "app/tests/" 27 | ``` 28 | 29 | ## Troubleshooting 30 | If standard logging of PHPCI is not enough, to get standard output from any command, including PHPUnit, edit `BaseCommandExecutor::executeCommand()` to see what exactly is wrong 31 | * Run `composer update` in phpunit plugin directory of PHPCI to get all of its dependencies 32 | * If phpunit is inside of the project's composer.json, it might interfere with PHPCI's phpunit installation 33 | * Make sure you have XDebug installed.`The Xdebug extension is not loaded. No code coverage will be generated.` 34 | Otherwise test report parsing in `TapParser` will fail, wanting coverage report as well `Invalid TAP string, number of tests does not match specified test count.` -------------------------------------------------------------------------------- /docs/source/postgresql-plugin.md: -------------------------------------------------------------------------------- 1 | Connects to a given PostgreSQL server and runs a list of queries. 2 | 3 | ### Example Configuration: 4 | 5 | ```yaml 6 | build_settings: 7 | pgsql: 8 | host: 'localhost' 9 | user: 'testuser' 10 | pass: '12345678' 11 | 12 | setup: 13 | pgsql: 14 | - "CREATE DATABASE my_app_test;" 15 | 16 | complete: 17 | pgsql: 18 | - "DROP DATABASE my_app_test;" 19 | ``` -------------------------------------------------------------------------------- /docs/source/project-status-images-and-page.md: -------------------------------------------------------------------------------- 1 | ### Status Image 2 | Most Continuous Integration systems provide a simple image URL that you can use to display your project status on other web sites (like Github) - PHPCI is no different. 3 | 4 | You can find the status image at the following location: `http://{PHPCI URL}/build-status/image/{PROJECT ID}` 5 | 6 | So for example, our instance of PHPCI is at `phpci.block8.net`, and our PHPCI project ID is `2`, so the image URL is: `http://phpci.block8.net/build-status/image/2`. 7 | 8 | Example: 9 | 10 | ![](http://phpci.block8.net/build-status/image/2) 11 | 12 | ### Status Page 13 | PHPCI also provides a public project status page, that is accessible for everyone. 14 | 15 | You can find the status page at the following location: `http://{PHPCI URL}/build-status/view/{PROJECT ID}` 16 | 17 | Example: 18 | http://phpci.block8.net/build-status/view/2 19 | 20 | #### Where do I find my project ID? 21 | Go to your instance of PHPCI, and open the project you are interested in. The project ID is the number in the last part of the URL in your browser. 22 | 23 | Example: 24 | http://phpci.block8.net/project/view/2 ~> PROJECT ID: `2` 25 | 26 | #### Enable/disable status image and page 27 | You can enable or disable access to the public status image and page in your project's settings. -------------------------------------------------------------------------------- /docs/source/run-builds-using-a-daemon.md: -------------------------------------------------------------------------------- 1 | # Run Builds Using a Daemon 2 | 3 | The PHPCI daemon runs in the background on your server and continuously checks for new builds. Unless already running a build, the daemon should pick up and start running new builds within seconds of being created. 4 | 5 | The daemon is also useful if you want to run multiple PHPCI workers in a virtualised environment (i.e. Docker) 6 | 7 | If you want to run PHPCI builds on a regular schedule instead, you should [set up a cron-job](Run-Builds-Using-Cron). 8 | 9 | ## Starting the Daemon 10 | 11 | On a Linux/Unix server, the following command will start the daemon and keep it running even when you log out of the server: 12 | 13 | ```sh 14 | nohup php ./daemonise phpci:daemonise >/dev/null 2>&1 & 15 | ``` 16 | 17 | If you need to debug what's going on with your builds, you can also run the daemon directly using the following command, which will output the daemon's log directly to your terminal: 18 | 19 | ```sh 20 | php daemonise phpci:daemonise 21 | ``` -------------------------------------------------------------------------------- /docs/source/run-builds-using-cron.md: -------------------------------------------------------------------------------- 1 | # Run Builds Using Cron 2 | 3 | Running builds using cron is a quick and simple method of getting up and running with PHPCI. It also removes the need for PHPCI to be running all the time. 4 | 5 | If you want a little more control over how PHPCI runs, you may want to [set up the PHPCI daemon](Run-Builds-Using-a-Daemon) instead. 6 | 7 | ## Setting up the Cron Job 8 | 9 | You'll want to set up PHPCI to run as a regular cronjob, so run `crontab -e` and enter the following: 10 | 11 | ```sh 12 | * * * * * /usr/bin/php /path/to/phpci/console phpci:run-builds 13 | ``` 14 | 15 | **Note:** Make sure you change the `/path/to/phpci` to the directory in which you installed PHPCI, and update the PHP path if necessary. -------------------------------------------------------------------------------- /docs/source/shell-plugin.md: -------------------------------------------------------------------------------- 1 | Runs a given Shell command. 2 | 3 | **Note: ** Because this plugin could potentially be abused, it requires extra steps to enable it: 4 | 5 | 1. In the root of your PHPCI system, in the same directory where you'll find composer.json and vars.php, look for a file local_vars.php. If it does not exist, create it. 6 | 2. In local_vars.php add this code: 7 | 8 | ```php 9 | - <%BUILD_URI%|Build #%BUILD%> has finished for commit <%COMMIT_URI%|%SHORT_COMMIT% (%COMMIT_EMAIL%)> on branch <%BRANCH_URI%|%BRANCH%>` | 12 | | `show_status` | No | Whether or not to append the build status as an attachment in slack. Default - true 13 | 14 | Send a message if the build fails: 15 | ```yaml 16 | failure: 17 | slack_notify: 18 | webhook_url: "https://hooks.slack.com/services/R212T827A/G983UY31U/aIp0yuW9u0iTqwAMOEwTg" 19 | room: "#phpci" 20 | username: "PHPCI" 21 | icon: ":ghost:" 22 | message: "%PROJECT_TITLE% - build %BUILD% failed! :angry:" 23 | show_status: false 24 | ``` 25 | 26 | Send a message if the build is successful: 27 | ```yaml 28 | 29 | success: 30 | slack_notify: 31 | webhook_url: "https://hooks.slack.com/services/R212T827A/G983UY31U/aIp0yuW9u0iTqwAMOEwTg" 32 | room: "#phpci" 33 | username: "PHPCI" 34 | icon: ":ghost:" 35 | message: "%PROJECT_TITLE% - build %BUILD% succeeded! :smiley:" 36 | show_status: false 37 | ``` 38 | 39 | Send a message every time the build runs: 40 | 41 | ```yaml 42 | complete: 43 | slack_notify: 44 | webhook_url: "https://hooks.slack.com/services/R212T827A/G983UY31U/aIp0yuW9u0iTqwAMOEwTg" 45 | room: "#phpci" 46 | username: "PHPCI" 47 | icon: ":ghost:" 48 | message: "%PROJECT_TITLE% - build %BUILD% completed" 49 | show_status: true 50 | ``` -------------------------------------------------------------------------------- /docs/source/technical-debt-plugin.md: -------------------------------------------------------------------------------- 1 | Checks all files in your project for TODOs and other technical debt. 2 | 3 | ## Configuration Options: 4 | 5 | * **searches** - Optional - Case-insensitive array of terms to search for. Defaults to TODO, TO DO, FIXME and FIX ME. -------------------------------------------------------------------------------- /docs/source/updating-phpci.md: -------------------------------------------------------------------------------- 1 | # Updating PHPCI 2 | 3 | Updating PHPCI to the latest release, or even dev-master updates is something that will need to be done from time to time. Most of this may be self-explanatory, but for clarity and completeness, it should be added to the documentation. 4 | 5 | 1. Go to your PHPCI root folder in a Terminal. 6 | 2. Pull the latest code. On Linux and Mac this would look like this: `git pull` 7 | 3. Update the composer and its packages: `composer self-update && composer install` 8 | 4. Update the PHPCI database: `./console phpci:update` 9 | 5. Return to the PHPCI admin screens and check your desired plugins are still installed correctly. 10 | 7. Run a build to make sure everything is working as expected. -------------------------------------------------------------------------------- /docs/source/xmpp-notifications-plugin.md: -------------------------------------------------------------------------------- 1 | ## Requirements 2 | - sendxmpp package 3 | 4 | ## Installation 5 | 1. On debian system (for example) use aptitude command to install sendxmpp 6 | 2. Add XMPP plugin in "complete" section of your phpci.yml 7 | 8 | ## Configuration options 9 | - username : Username of your XMPP sender account. (example : login@server.com) 10 | - password : Password of your XMPP sender account. 11 | - recipients : List of your XMPP recipents account. 12 | - server : If your server is not the same that your login server (optional, example : gtalk.google.com) 13 | - tls : Set 1 to enable TLS connection or 0 to disable it. (optional, default is 0) 14 | - alias : Alias of your sender account. (optional) 15 | - date_format : strftime mask date format display in notification message. (optional, default is %c of strftime function) 16 | 17 | ## Configuration example 18 | 19 | ``` 20 | complete: 21 | xmpp: 22 | username: "login@gmail.com" 23 | password: "AZERTY123" 24 | recipients: 25 | - "recipient1@jabber.org" 26 | - "recipient2@jabber.org" 27 | server: "gtalk.google.com" 28 | tls: 1 29 | alias: "PHPCi Notification" 30 | date_format: "%d/%m/%Y" 31 | ``` -------------------------------------------------------------------------------- /loggerconfig.php.example: -------------------------------------------------------------------------------- 1 | function() { 14 | return array( 15 | new \Monolog\Handler\StreamHandler(__DIR__ . DIRECTORY_SEPARATOR . 'errors.log', \Monolog\Logger::ERROR), 16 | ); 17 | }, 18 | /** Loggers for the RunCommand */ 19 | 'RunCommand' => function() { 20 | return array( 21 | new \Monolog\Handler\RotatingFileHandler(__DIR__ . DIRECTORY_SEPARATOR . 'everything',3, \Monolog\Logger::DEBUG), 22 | ); 23 | }, 24 | ); 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "dependencies": { 4 | "admin-lte": "^2.4.8", 5 | "moment": "^2.22.2", 6 | "sprintf-js": "^1.1.1", 7 | "jquery-ui": "^1.12.1" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /phinx.php: -------------------------------------------------------------------------------- 1 | get('b8.database.servers.write'); 14 | 15 | if (!is_array($writeServers)) { 16 | $writeServers = array($writeServers); 17 | } 18 | 19 | $conf = array( 20 | 'paths' => array( 21 | 'migrations' => 'PHPCI/Migrations', 22 | ), 23 | 24 | 'environments' => array( 25 | 'default_migration_table' => 'migration', 26 | 'default_database' => 'phpci', 27 | 'phpci' => array( 28 | 'adapter' => 'mysql', 29 | 'host' => end($writeServers), 30 | 'name' => $config->get('b8.database.name'), 31 | 'user' => $config->get('b8.database.username'), 32 | 'pass' => $config->get('b8.database.password'), 33 | ), 34 | ), 35 | ); 36 | 37 | return $conf; 38 | -------------------------------------------------------------------------------- /phpcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Codestyle ruleset for PHPCI 5 | 6 | 7 | 8 | PHPCI 9 | 10 | 11 | 12 | 13 | PHPCI/Migrations/* 14 | PHPCI/Model/Base/* 15 | PHPCI/Languages/* 16 | Tests/* 17 | vendor/* 18 | 19 | 20 | -------------------------------------------------------------------------------- /phpmd.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | PHPCI rule set 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 15 | ./Tests/PHPCI/Command 16 | 17 | 18 | ./Tests/PHPCI/Helper 19 | 20 | 21 | ./Tests/PHPCI/Logging 22 | 23 | 24 | ./Tests/PHPCI/Plugin 25 | 26 | 27 | ./Tests/PHPCI/Model 28 | 29 | 30 | ./Tests/PHPCI/Service 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /pluginconfig.php.example: -------------------------------------------------------------------------------- 1 | registerResource( 4 | // This function will be called when the resource is needed. 5 | function() { 6 | return array( 7 | 'Foo' => "Stuff", 8 | 'Bar' => "More Stuff" 9 | ); 10 | }, 11 | 12 | // In addition to the function for building the resource the system 13 | // also needs to be told when to load the resource. Either or both 14 | // of the following arguments can be used (null to ignore) 15 | 16 | // This resource will only be given when the argument name is: 17 | "ResourceArray", 18 | 19 | // The resource will only be given when the type hint is: 20 | PHPCI\Plugin\Util\Factory::TYPE_ARRAY 21 | ); 22 | }; 23 | -------------------------------------------------------------------------------- /public/.htaccess.dist: -------------------------------------------------------------------------------- 1 | 2 | RewriteEngine On 3 | RewriteBase / 4 | RewriteCond %{REQUEST_FILENAME} !-f 5 | RewriteCond %{REQUEST_FILENAME} !-d 6 | RewriteRule . /index.php [L] 7 | 8 | -------------------------------------------------------------------------------- /public/assets/css/AdminLTE-custom.css: -------------------------------------------------------------------------------- 1 | .phpci .main-header .logo, .phpci .main-header .logo:hover { 2 | background-image: url('/assets/img/logo-large.png'); 3 | background-repeat: no-repeat; 4 | background-size: 40%; 5 | background-position: 65px; 6 | text-indent: -5000px; 7 | } 8 | 9 | .build-info-panel { 10 | 11 | } 12 | 13 | .build-info-panel .box-header h1.box-title { 14 | border: 0; 15 | font-size: 1.5em; 16 | font-weight: bold; 17 | margin-left: 110px; 18 | } 19 | 20 | .build-info-panel h1.box-title span { 21 | font-weight: normal; 22 | } 23 | 24 | .build-info-panel img { 25 | border: 2px solid #fff; 26 | border-radius: 50%; 27 | margin-top: -40px; 28 | } 29 | 30 | .build-info-panel #build-info { 31 | margin-left: 110px; 32 | min-height: 50px; 33 | } 34 | 35 | .build-info-panel .commit-message { 36 | margin-bottom: 20px; 37 | } 38 | 39 | .small-box h3 a, .small-box h4 a { 40 | color: #fff; 41 | } 42 | 43 | .pagination>li>span { 44 | font-weight: bold; 45 | background: #337ab7; 46 | color: #fff; 47 | } 48 | 49 | #plugins table td { 50 | max-width: 300px; 51 | overflow: hidden; 52 | text-overflow: ellipsis; 53 | } 54 | 55 | .small-box > .inner { 56 | border-bottom: 1px solid rgba(0, 0, 0, 0.15); 57 | } 58 | 59 | .small-box > .small-box-footer-project { 60 | width: 60%; 61 | float: left; 62 | } 63 | .small-box > .small-box-footer-build { 64 | width: 8%; 65 | float: left; 66 | } 67 | .small-box-minimal > .inner { 68 | width: 71%; 69 | float: left; 70 | } 71 | .small-box-minimal > .small-box-footer-build { 72 | width: 5%; 73 | border: 1px solid rgba(0, 0, 0, 0.15); 74 | margin-left: 1px; 75 | margin-top: 19px; 76 | font-size: 11px; 77 | } 78 | 79 | #phpunit-data th div { margin: 0 0.5em; } 80 | #phpunit-data .success td { background: none; color: #00a65a; } 81 | #phpunit-data .fail td { background: none; color: #f56954; } 82 | #phpunit-data .error td { background: none; color: #f56954; } 83 | #phpunit-data .skipped td { background: none; color: #e08e0b; } 84 | #phpunit-data .todo td { background: none; color: #00c0ef; } 85 | 86 | .ml20px { 87 | margin-left: 20px 88 | } 89 | -------------------------------------------------------------------------------- /public/assets/css/ansi-colors.css: -------------------------------------------------------------------------------- 1 | .ansi_color_bg_black { background-color: #FFF } 2 | .ansi_color_bg_red { background-color: #900 } 3 | .ansi_color_bg_green { background-color: #090 } 4 | .ansi_color_bg_yellow { background-color: #990 } 5 | .ansi_color_bg_blue { background-color: #009 } 6 | .ansi_color_bg_magenta { background-color: #909 } 7 | .ansi_color_bg_cyan { background-color: #099 } 8 | .ansi_color_bg_white { background-color: #000 } 9 | .ansi_color_bg_brblack { background-color: #FFF } 10 | .ansi_color_bg_brred { background-color: #F00 } 11 | .ansi_color_bg_brgreen { background-color: #0F0 } 12 | .ansi_color_bg_bryellow { background-color: #FF0 } 13 | .ansi_color_bg_brblue { background-color: #00F } 14 | .ansi_color_bg_brmagenta { background-color: #F0F } 15 | .ansi_color_bg_brcyan { background-color: #0FF } 16 | .ansi_color_bg_brwhite { background-color: #000 } 17 | 18 | .ansi_color_fg_black { color: #FFF } 19 | .ansi_color_fg_red { color: #900 } 20 | .ansi_color_fg_green { color: #090 } 21 | .ansi_color_fg_yellow { color: #990 } 22 | .ansi_color_fg_blue { color: #009 } 23 | .ansi_color_fg_magenta { color: #909 } 24 | .ansi_color_fg_cyan { color: #099 } 25 | .ansi_color_fg_white { color: #000 } 26 | .ansi_color_fg_brblack { color: #FFF } 27 | .ansi_color_fg_brred { color: #F00 } 28 | .ansi_color_fg_brgreen { color: #0F0 } 29 | .ansi_color_fg_bryellow { color: #FF0 } 30 | .ansi_color_fg_brblue { color: #00F } 31 | .ansi_color_fg_brmagenta { color: #F0F } 32 | .ansi_color_fg_brcyan { color: #0FF } 33 | .ansi_color_fg_brwhite { color: #000 } 34 | -------------------------------------------------------------------------------- /public/assets/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dancryer/PHPCI/71ab3875ac822c8f138e4dddd045cc992229811e/public/assets/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /public/assets/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dancryer/PHPCI/71ab3875ac822c8f138e4dddd045cc992229811e/public/assets/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /public/assets/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dancryer/PHPCI/71ab3875ac822c8f138e4dddd045cc992229811e/public/assets/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /public/assets/img/ajax-loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dancryer/PHPCI/71ab3875ac822c8f138e4dddd045cc992229811e/public/assets/img/ajax-loader.gif -------------------------------------------------------------------------------- /public/assets/img/ajax-loader1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dancryer/PHPCI/71ab3875ac822c8f138e4dddd045cc992229811e/public/assets/img/ajax-loader1.gif -------------------------------------------------------------------------------- /public/assets/img/blur-background04.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dancryer/PHPCI/71ab3875ac822c8f138e4dddd045cc992229811e/public/assets/img/blur-background04.jpg -------------------------------------------------------------------------------- /public/assets/img/blur-background08.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dancryer/PHPCI/71ab3875ac822c8f138e4dddd045cc992229811e/public/assets/img/blur-background08.jpg -------------------------------------------------------------------------------- /public/assets/img/blur-background09.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dancryer/PHPCI/71ab3875ac822c8f138e4dddd045cc992229811e/public/assets/img/blur-background09.jpg -------------------------------------------------------------------------------- /public/assets/img/bootstrap-colorpicker/alpha-horizontal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dancryer/PHPCI/71ab3875ac822c8f138e4dddd045cc992229811e/public/assets/img/bootstrap-colorpicker/alpha-horizontal.png -------------------------------------------------------------------------------- /public/assets/img/bootstrap-colorpicker/alpha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dancryer/PHPCI/71ab3875ac822c8f138e4dddd045cc992229811e/public/assets/img/bootstrap-colorpicker/alpha.png -------------------------------------------------------------------------------- /public/assets/img/bootstrap-colorpicker/hue-horizontal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dancryer/PHPCI/71ab3875ac822c8f138e4dddd045cc992229811e/public/assets/img/bootstrap-colorpicker/hue-horizontal.png -------------------------------------------------------------------------------- /public/assets/img/bootstrap-colorpicker/hue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dancryer/PHPCI/71ab3875ac822c8f138e4dddd045cc992229811e/public/assets/img/bootstrap-colorpicker/hue.png -------------------------------------------------------------------------------- /public/assets/img/bootstrap-colorpicker/saturation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dancryer/PHPCI/71ab3875ac822c8f138e4dddd045cc992229811e/public/assets/img/bootstrap-colorpicker/saturation.png -------------------------------------------------------------------------------- /public/assets/img/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dancryer/PHPCI/71ab3875ac822c8f138e4dddd045cc992229811e/public/assets/img/favicon.png -------------------------------------------------------------------------------- /public/assets/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dancryer/PHPCI/71ab3875ac822c8f138e4dddd045cc992229811e/public/assets/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /public/assets/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dancryer/PHPCI/71ab3875ac822c8f138e4dddd045cc992229811e/public/assets/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /public/assets/img/icon-build-failed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dancryer/PHPCI/71ab3875ac822c8f138e4dddd045cc992229811e/public/assets/img/icon-build-failed.png -------------------------------------------------------------------------------- /public/assets/img/icon-build-ok.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dancryer/PHPCI/71ab3875ac822c8f138e4dddd045cc992229811e/public/assets/img/icon-build-ok.png -------------------------------------------------------------------------------- /public/assets/img/icon-build-pending.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dancryer/PHPCI/71ab3875ac822c8f138e4dddd045cc992229811e/public/assets/img/icon-build-pending.png -------------------------------------------------------------------------------- /public/assets/img/icon-build-running.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dancryer/PHPCI/71ab3875ac822c8f138e4dddd045cc992229811e/public/assets/img/icon-build-running.png -------------------------------------------------------------------------------- /public/assets/img/icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dancryer/PHPCI/71ab3875ac822c8f138e4dddd045cc992229811e/public/assets/img/icons.png -------------------------------------------------------------------------------- /public/assets/img/logo-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dancryer/PHPCI/71ab3875ac822c8f138e4dddd045cc992229811e/public/assets/img/logo-icon.png -------------------------------------------------------------------------------- /public/assets/img/logo-icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/assets/img/logo-large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dancryer/PHPCI/71ab3875ac822c8f138e4dddd045cc992229811e/public/assets/img/logo-large.png -------------------------------------------------------------------------------- /public/assets/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dancryer/PHPCI/71ab3875ac822c8f138e4dddd045cc992229811e/public/assets/img/logo.png -------------------------------------------------------------------------------- /public/assets/img/sprite-skin-flat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dancryer/PHPCI/71ab3875ac822c8f138e4dddd045cc992229811e/public/assets/img/sprite-skin-flat.png -------------------------------------------------------------------------------- /public/assets/img/sprite-skin-nice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dancryer/PHPCI/71ab3875ac822c8f138e4dddd045cc992229811e/public/assets/img/sprite-skin-nice.png -------------------------------------------------------------------------------- /public/assets/img/user-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dancryer/PHPCI/71ab3875ac822c8f138e4dddd045cc992229811e/public/assets/img/user-bg.png -------------------------------------------------------------------------------- /public/assets/img/user.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dancryer/PHPCI/71ab3875ac822c8f138e4dddd045cc992229811e/public/assets/img/user.jpg -------------------------------------------------------------------------------- /public/assets/img/user2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dancryer/PHPCI/71ab3875ac822c8f138e4dddd045cc992229811e/public/assets/img/user2.jpg -------------------------------------------------------------------------------- /public/assets/js/build-plugins/phpspec.js: -------------------------------------------------------------------------------- 1 | var phpspecPlugin = ActiveBuild.UiPlugin.extend({ 2 | id: 'build-phpspec-errors', 3 | css: 'col-lg-12 col-md-12 col-sm-12 col-xs-12', 4 | title: Lang.get('phpspec'), 5 | lastData: null, 6 | displayOnUpdate: false, 7 | box: true, 8 | rendered: false, 9 | 10 | register: function() { 11 | var self = this; 12 | var query = ActiveBuild.registerQuery('phpspec', -1, {key: 'phpspec'}) 13 | 14 | $(window).on('phpspec', function(data) { 15 | self.onUpdate(data); 16 | }); 17 | 18 | $(window).on('build-updated', function() { 19 | if (!self.rendered) { 20 | self.displayOnUpdate = true; 21 | query(); 22 | } 23 | }); 24 | }, 25 | 26 | render: function() { 27 | 28 | return $('' + 29 | '' + 30 | '' + 31 | ' ' + 32 | ' ' + 33 | ' ' + 34 | '' + 35 | '
    '+Lang.get('suite')+''+Lang.get('test')+''+Lang.get('result')+'
    '); 36 | }, 37 | 38 | onUpdate: function(e) { 39 | if (!e.queryData) { 40 | $('#build-phpspec-errors').hide(); 41 | return; 42 | } 43 | 44 | this.rendered = true; 45 | this.lastData = e.queryData; 46 | 47 | var tests = this.lastData[0].meta_value; 48 | var tbody = $('#phpspec-data tbody'); 49 | tbody.empty(); 50 | 51 | for (var i in tests.suites) { 52 | var test_suite = tests.suites[i]; 53 | 54 | for(var k in test_suite.cases){ 55 | var test_case = test_suite.cases[k]; 56 | 57 | var row = $( 58 | ''+ 59 | ''+test_suite.name+''+ 60 | ''+test_case.name+''+ 61 | ''+(test_case.message ? test_case.message : Lang.get('ok'))+''+ 62 | '' 63 | ); 64 | 65 | if (test_case.status!='passed') { 66 | row.addClass('danger'); 67 | } else { 68 | row.addClass('success'); 69 | } 70 | 71 | tbody.append(row); 72 | } 73 | } 74 | 75 | // show plugin once preparation of grid is done 76 | $('#build-phpspec-errors').show(); 77 | } 78 | }); 79 | 80 | ActiveBuild.registerPlugin(new phpspecPlugin()); 81 | -------------------------------------------------------------------------------- /public/assets/js/build-plugins/phptallint.js: -------------------------------------------------------------------------------- 1 | var phptalPlugin = ActiveBuild.UiPlugin.extend({ 2 | id: 'build-phptal', 3 | css: 'col-lg-6 col-md-12 col-sm-12 col-xs-12', 4 | title: 'PHPTAL Lint', 5 | lastData: null, 6 | box: true, 7 | rendered: false, 8 | 9 | register: function() { 10 | var self = this; 11 | var query = ActiveBuild.registerQuery('phptallint-data', -1, {key: 'phptallint-data'}) 12 | 13 | $(window).on('phptallint-data', function(data) { 14 | self.onUpdate(data); 15 | }); 16 | 17 | $(window).on('build-updated', function() { 18 | if (!self.rendered) { 19 | query(); 20 | } 21 | }); 22 | }, 23 | 24 | render: function() { 25 | return $('
    ' + 26 | '' + 27 | '' + 28 | ' ' + 29 | ' ' + 30 | ' ' + 31 | '' + 32 | '
    FileLineMessage
    '); 33 | }, 34 | 35 | onUpdate: function(e) { 36 | if (!e.queryData) { 37 | $('#build-phptal').hide(); 38 | return; 39 | } 40 | 41 | this.rendered = true; 42 | this.lastData = e.queryData; 43 | 44 | var errors = this.lastData[0].meta_value; 45 | var tbody = $('#phptal-data tbody'); 46 | tbody.empty(); 47 | 48 | if (errors.length == 0) { 49 | $('#build-phptal').hide(); 50 | return; 51 | } 52 | 53 | for (var i in errors) { 54 | var file = errors[i].file; 55 | 56 | if (ActiveBuild.fileLinkTemplate) { 57 | var fileLink = ActiveBuild.fileLinkTemplate.replace('{FILE}', file); 58 | fileLink = fileLink.replace('{LINE}', errors[i].line); 59 | 60 | file = '' + file + ''; 61 | } 62 | 63 | var row = $('' + 64 | ''+file+'' + 65 | ''+errors[i].line+'' + 66 | ''+errors[i].message+''); 67 | 68 | if (errors[i].type == 'error') { 69 | row.addClass('danger'); 70 | } 71 | 72 | tbody.append(row); 73 | } 74 | 75 | $('#build-phptal').show(); 76 | } 77 | }); 78 | 79 | ActiveBuild.registerPlugin(new phptalPlugin()); 80 | -------------------------------------------------------------------------------- /public/assets/js/class.js: -------------------------------------------------------------------------------- 1 | /* Simple JavaScript Inheritance 2 | * By John Resig http://ejohn.org/ 3 | * MIT Licensed. 4 | */ 5 | // Inspired by base2 and Prototype 6 | (function(){ 7 | var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/; 8 | 9 | // The base Class implementation (does nothing) 10 | this.Class = function(){}; 11 | 12 | // Create a new Class that inherits from this class 13 | Class.extend = function(prop) { 14 | var _super = this.prototype; 15 | 16 | // Instantiate a base class (but only create the instance, 17 | // don't run the init constructor) 18 | initializing = true; 19 | var prototype = new this(); 20 | initializing = false; 21 | 22 | // Copy the properties over onto the new prototype 23 | for (var name in prop) { 24 | // Check if we're overwriting an existing function 25 | prototype[name] = typeof prop[name] == "function" && 26 | typeof _super[name] == "function" && fnTest.test(prop[name]) ? 27 | (function(name, fn){ 28 | return function() { 29 | var tmp = this._super; 30 | 31 | // Add a new ._super() method that is the same method 32 | // but on the super-class 33 | this._super = _super[name]; 34 | 35 | // The method only need to be bound temporarily, so we 36 | // remove it when we're done executing 37 | var ret = fn.apply(this, arguments); 38 | this._super = tmp; 39 | 40 | return ret; 41 | }; 42 | })(name, prop[name]) : 43 | prop[name]; 44 | } 45 | 46 | // The dummy class constructor 47 | function Class() { 48 | // All construction is actually done in the init method 49 | if ( !initializing && this.init ) 50 | this.init.apply(this, arguments); 51 | } 52 | 53 | // Populate our constructed prototype object 54 | Class.prototype = prototype; 55 | 56 | // Enforce the constructor to be what we expect 57 | Class.prototype.constructor = Class; 58 | 59 | // And make this class extendable 60 | Class.extend = arguments.callee; 61 | 62 | return Class; 63 | }; 64 | })(); -------------------------------------------------------------------------------- /public/assets/js/init.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file init.js 3 | * Initialization of frontend of the application goes here 4 | * 5 | * @author Pavel Pavlov 6 | * @date 12/31/13 7 | * @time 3:44 AM 8 | * @license LICENSE.md 9 | * 10 | * @package PHPCI 11 | */ 12 | 13 | $(function () { 14 | $('#latest-builds').on('latest-builds:reload', bindAppDeleteEvents); 15 | $('#latest-builds').trigger('latest-builds:reload'); 16 | }); 17 | 18 | function bindAppDeleteEvents () { 19 | $('.phpci-app-delete-build').on('click', function (e) { 20 | e.preventDefault(); 21 | 22 | confirmDelete(e.target.href, 'Build').onClose = function () { 23 | window.location.reload(); 24 | }; 25 | 26 | return false; 27 | }); 28 | 29 | $('.phpci-app-delete-user').on('click', function (e) { 30 | e.preventDefault(); 31 | 32 | confirmDelete(e.target.href, 'User', true); 33 | 34 | return false; 35 | }); 36 | } 37 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dancryer/PHPCI/71ab3875ac822c8f138e4dddd045cc992229811e/public/favicon.ico -------------------------------------------------------------------------------- /public/index.php: -------------------------------------------------------------------------------- 1 | handleRequest(); 17 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-Agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /vars.php: -------------------------------------------------------------------------------- 1 | get('phpci.url', '') . '/'); 12 | } 13 | 14 | // Define PHPCI_BIN_DIR 15 | if (!defined('PHPCI_BIN_DIR')) { 16 | define('PHPCI_BIN_DIR', PHPCI_DIR . 'vendor/bin/'); 17 | } 18 | 19 | // Define PHPCI_BUILD_ROOT_DIR 20 | if (!defined('PHPCI_BUILD_ROOT_DIR')) { 21 | define('PHPCI_BUILD_ROOT_DIR', PHPCI_DIR . 'PHPCI/build/'); 22 | } 23 | 24 | // Should PHPCI run the Shell plugin? 25 | if (!defined('ENABLE_SHELL_PLUGIN')) { 26 | define('ENABLE_SHELL_PLUGIN', false); 27 | } 28 | 29 | // If this is not already defined, we're not running in the console: 30 | if (!defined('PHPCI_IS_CONSOLE')) { 31 | define('PHPCI_IS_CONSOLE', false); 32 | } 33 | 34 | if (!defined('IS_WIN')) { 35 | define('IS_WIN', ((strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') ? true : false)); 36 | } 37 | 38 | // If an environment variable is set defining our config location, use that 39 | // otherwise fall back to PHPCI/config.yml. 40 | if (!defined('PHPCI_CONFIG_FILE')) { 41 | define('PHPCI_CONFIG_FILE', $configFile); 42 | } 43 | --------------------------------------------------------------------------------