Initial implementation CI environments

This commit is contained in:
Stepan Strelets 2017-03-23 15:53:24 +03:00 committed by Dmitry Khomutov
parent 7f8b0234b9
commit 047cedaab3
No known key found for this signature in database
GPG key ID: 7EB36C9576F9ECB9
21 changed files with 850 additions and 42 deletions

View file

@ -38,7 +38,7 @@ var PHPCensor = {
getProjectBuilds: function () {
$.ajax({
url: APP_URL + 'project/ajax-builds/' + PROJECT_ID + '?branch=' + PROJECT_BRANCH + '&per_page=' + PER_PAGE,
url: APP_URL + 'project/ajax-builds/' + PROJECT_ID + '?branch=' + PROJECT_BRANCH + '&environment=' + PROJECT_ENVIRONMENT + '&per_page=' + PER_PAGE,
success: function (data) {
$('#latest-builds').html(data);

View file

@ -60,6 +60,7 @@ class CreateBuildCommand extends Command
$projectId = $input->getArgument('projectId');
$commitId = $input->getOption('commit');
$branch = $input->getOption('branch');
$environment = $input->getOption('environment');
$project = $this->projectStore->getById($projectId);
if (empty($project) || $project->getArchived()) {
@ -67,7 +68,7 @@ class CreateBuildCommand extends Command
}
try {
$this->buildService->createBuild($project, $commitId, $branch);
$this->buildService->createBuild($project, $environment, $commitId, $branch);
$output->writeln('Build Created');
} catch (\Exception $e) {
$output->writeln('<error>Failed</error>');

View file

@ -58,6 +58,7 @@ class ProjectController extends PHPCensor\Controller
public function view($projectId)
{
$branch = $this->getParam('branch', '');
$environment = $this->getParam('environment', '');
$project = $this->projectStore->getById($projectId);
if (empty($project)) {
@ -66,7 +67,7 @@ class ProjectController extends PHPCensor\Controller
$perPage = $_SESSION['php-censor-user']->getFinalPerPage();
$page = $this->getParam('p', 1);
$builds = $this->getLatestBuildsHtml($projectId, urldecode($branch), (($page - 1) * $perPage), $perPage);
$builds = $this->getLatestBuildsHtml($projectId, urldecode($environment), urlencode($branch), (($page - 1) * $perPage), $perPage);
$pages = $builds[1] == 0 ? 1 : ceil($builds[1] / $perPage);
if ($page > $pages) {
@ -80,12 +81,18 @@ class ProjectController extends PHPCensor\Controller
$this->view->project = $project;
$this->view->branch = urldecode($branch);
$this->view->branches = $this->projectStore->getKnownBranches($projectId);
$this->view->environment = urldecode($environment);
$this->view->environments = $project->getEnvironmentsNames();
$this->view->page = $page;
$this->view->pages = $pages;
$this->view->perPage = $perPage;
$this->layout->title = $project->getTitle();
$this->layout->subtitle = $this->view->branch;
if (!empty($this->view->environment)) {
$this->layout->subtitle = $this->view->environment;
} else {
$this->layout->subtitle = $this->view->branch;
}
return $this->view->render();
}
@ -93,11 +100,22 @@ class ProjectController extends PHPCensor\Controller
/**
* Create a new pending build for a project.
*/
public function build($projectId, $branch = '')
public function build($projectId, $type = null, $id = null)
{
/* @var \PHPCensor\Model\Project $project */
$project = $this->projectStore->getById($projectId);
$environment = null;
$branch = null;
switch($type) {
case 'environment':
$environment = $id;
break;
case 'branch':
$branch = $id;
break;
}
if (empty($branch)) {
$branch = $project->getBranch();
}
@ -115,7 +133,7 @@ class ProjectController extends PHPCensor\Controller
}
$email = $_SESSION['php-censor-user']->getEmail();
$build = $this->buildService->createBuild($project, null, urldecode($branch), $email, null, $extra);
$build = $this->buildService->createBuild($project, $environment, null, urldecode($branch), $email, null, $extra);
if ($this->buildService->queueError) {
$_SESSION['global_error'] = Lang::get('add_to_queue_failed');
@ -145,15 +163,19 @@ class ProjectController extends PHPCensor\Controller
* Render latest builds for project as HTML table.
*
* @param int $projectId
* @param string $environment A urldecoded environment name.
* @param string $branch A urldecoded branch name.
* @param int $start
* @param int $perPage
*
* @return array
*/
protected function getLatestBuildsHtml($projectId, $branch = '', $start = 0, $perPage = 10)
protected function getLatestBuildsHtml($projectId, $environment = '', $branch = '', $start = 0, $perPage = 10)
{
$criteria = ['project_id' => $projectId];
if (!empty($environment)) {
$criteria['environment'] = $environment;
}
if (!empty($branch)) {
$criteria['branch'] = $branch;
}
@ -276,6 +298,8 @@ class ProjectController extends PHPCensor\Controller
$values['key'] = $values['ssh_private_key'];
$values['pubkey'] = $values['ssh_public_key'];
$values['environments'] = $project->getEnvironments();
if ($values['type'] == 'gitlab') {
$accessInfo = $project->getAccessInformation();
$reference = $accessInfo["user"] . '@' . $accessInfo["domain"] . ':' . $accessInfo["port"] . '/' . ltrim($project->getReference(), '/') . ".git";
@ -310,6 +334,7 @@ class ProjectController extends PHPCensor\Controller
'archived' => $this->getParam('archived', 0),
'branch' => $this->getParam('branch', null),
'group' => $this->getParam('group_id', null),
'environments' => $this->getParam('environments', null),
];
$project = $this->projectService->updateProject($project, $title, $type, $reference, $options);
@ -381,6 +406,13 @@ class ProjectController extends PHPCensor\Controller
$field->setClass('form-control')->setContainerClass('form-group')->setValue('master');
$form->addField($field);
if ($type != 'add') {
$field = Form\Element\TextArea::create('environments', Lang::get('environments_label'), false);
$field->setClass('form-control')->setContainerClass('form-group');
$field->setRows(6);
$form->addField($field);
}
$field = Form\Element\Select::create('group_id', Lang::get('project_group'), true);
$field->setClass('form-control')->setContainerClass('form-group')->setValue(1);
@ -472,8 +504,9 @@ class ProjectController extends PHPCensor\Controller
public function ajaxBuilds($projectId)
{
$branch = $this->getParam('branch', '');
$environment = $this->getParam('environment', '');
$perPage = (integer)$this->getParam('per_page', 10);
$builds = $this->getLatestBuildsHtml($projectId, urldecode($branch), 0, $perPage);
$builds = $this->getLatestBuildsHtml($projectId, urldecode($environment), urldecode($branch), 0, $perPage);
$this->response->disableLayout();
$this->response->setContent($builds[0]);

View file

@ -6,6 +6,7 @@ use b8;
use b8\Store;
use Exception;
use PHPCensor\Helper\Lang;
use PHPCensor\Model\Build;
use PHPCensor\Model\Project;
use PHPCensor\Service\BuildService;
use PHPCensor\Store\BuildStore;
@ -510,17 +511,57 @@ class WebhookController extends Controller
// Check if a build already exists for this commit ID:
$builds = $this->buildStore->getByProjectAndCommit($project->getId(), $commitId);
$ignore_environments = [];
if ($builds['count']) {
return [
'status' => 'ignored',
'message' => sprintf('Duplicate of build #%d', $builds['items'][0]->getId())
];
foreach($builds['items'] as $build) {
/** @var Build $build */
$ignore_environments[$build->getId()] = $build->getEnvironment();
}
}
// If not, create a new build job for it:
$build = $this->buildService->createBuild($project, $commitId, $branch, $committer, $commitMessage, $extra);
return ['status' => 'ok', 'buildID' => $build->getID()];
$environments = $project->getEnvironmentsObjects();
if ($environments['count']) {
$created_builds = [];
$environment_names = $project->getEnvironmentsNamesByBranch($branch);
// use base branch from project
if (!empty($environment_names)) {
$duplicates = [];
foreach ($environment_names as $environment_name) {
if (!in_array($environment_name, $ignore_environments)) {
// If not, create a new build job for it:
$build = $this->buildService->createBuild($project, $environment_name, $commitId, $project->getBranch(), $committer, $commitMessage, $extra);
$created_builds[] = array(
'id' => $build->getID(),
'environment' => $environment_name,
);
} else {
$duplicates[] = array_search($environment_name, $ignore_environments);
}
}
if (!empty($created_builds)) {
if (empty($duplicates)) {
return ['status' => 'ok', 'builds' => $created_builds];
} else {
return ['status' => 'ok', 'builds' => $created_builds, 'message' => sprintf('For this commit some builds already exists (%s)', implode(', ', $duplicates))];
}
} else {
return ['status' => 'ignored', 'message' => sprintf('For this commit already created builds (%s)', implode(', ', $duplicates))];
}
} else {
return ['status' => 'ignored', 'message' => 'Branch not assigned to any environment'];
}
} else {
$environment_name = null;
if (!in_array($environment_name, $ignore_environments)) {
$build = $this->buildService->createBuild($project, null, $commitId, $branch, $committer, $commitMessage, $extra);
return ['status' => 'ok', 'buildID' => $build->getID()];
} else {
return [
'status' => 'ignored',
'message' => sprintf('Duplicate of build #%d', array_search($environment_name, $ignore_environments)),
];
}
}
}
/**

View file

@ -37,6 +37,7 @@ class BuildInterpolator
$this->interpolation_vars['%COMMIT_URI%'] = $build->getCommitLink();
$this->interpolation_vars['%BRANCH%'] = $build->getBranch();
$this->interpolation_vars['%BRANCH_URI%'] = $build->getBranchLink();
$this->interpolation_vars['%ENVIRONMENT%'] = $build->getEnvironment();
$this->interpolation_vars['%PROJECT%'] = $build->getProjectId();
$this->interpolation_vars['%BUILD%'] = $build->getId();
$this->interpolation_vars['%PROJECT_TITLE%'] = $build->getProjectTitle();

View file

@ -48,6 +48,7 @@ PHP Censor',
'branch_x' => 'Branch: %s',
'created_x' => 'Created: %s',
'started_x' => 'Started: %s',
'environment_x' => 'Environment: %s',
// Sidebar
'hello_name' => 'Hello, %s',
@ -117,6 +118,7 @@ PHP Censor',
'archived' => 'Archived',
'archived_menu' => 'Archived',
'save_project' => 'Save Project',
'environments_label' => 'Environments (yaml)',
'error_mercurial' => 'Mercurial repository URL must be start with http:// or https://',
'error_remote' => 'Repository URL must be start with git://, http:// or https://',
@ -127,12 +129,14 @@ PHP Censor',
// View Project:
'all_branches' => 'All Branches',
'all' => 'All',
'builds' => 'Builds',
'id' => 'ID',
'date' => 'Date',
'project' => 'Project',
'commit' => 'Commit',
'branch' => 'Branch',
'environment' => 'Environment',
'status' => 'Status',
'prev_link' => '&laquo; Prev',
'next_link' => 'Next &raquo;',
@ -194,6 +198,7 @@ PHP Censor',
'phpcpd_warnings' => 'PHP Copy/Paste Detector warnings',
'phpdoccheck_warnings' => 'Missing docblocks',
'issues' => 'Issues',
'merged_branches' => 'Merged branches',
'phpcpd' => 'PHP Copy/Paste Detector',
'phpcs' => 'PHP Code Sniffer',

View file

@ -0,0 +1,52 @@
<?php
use Phinx\Migration\AbstractMigration;
class AddEnvironment extends AbstractMigration
{
public function up()
{
$table = $this->table('environment');
if (!$this->hasTable('environment')) {
$table->create();
}
if (!$table->hasColumn('project_id')) {
$table->addColumn('project_id', 'integer')->save();
}
if (!$table->hasColumn('name')) {
$table->addColumn('name', 'string', ['limit' => 20])->save();
}
if (!$table->hasColumn('branches')) {
$table->addColumn('branches', 'text')->save();
}
if (!$table->hasIndex(['project_id', 'name'])) {
$table->addIndex(['project_id', 'name'])->save();
}
$table = $this->table('build');
if (!$table->hasColumn('environment')) {
$table->addColumn('environment', 'string', ['limit' => 20])->save();
}
}
public function down()
{
$table = $this->table('environment');
if ($this->hasTable('environment')) {
$table->drop();
}
$table = $this->table('build');
if ($table->hasColumn('environment')) {
$table->removeColumn('environment')->save();
}
}
}

View file

@ -52,6 +52,7 @@ class Build extends Model
'committer_email' => null,
'commit_message' => null,
'extra' => null,
'environment' => null,
];
/**
@ -71,6 +72,7 @@ class Build extends Model
'committer_email' => 'getCommitterEmail',
'commit_message' => 'getCommitMessage',
'extra' => 'getExtra',
'environment' => 'getEnvironment',
// Foreign key getters:
'Project' => 'getProject',
@ -93,6 +95,7 @@ class Build extends Model
'committer_email' => 'setCommitterEmail',
'commit_message' => 'setCommitMessage',
'extra' => 'setExtra',
'environment' => 'setEnvironment',
// Foreign key setters:
'Project' => 'setProject',
@ -165,6 +168,11 @@ class Build extends Model
'nullable' => true,
'default' => null,
],
'environment' => [
'type' => 'varchar',
'length' => 20,
'default' => null,
],
];
/**
@ -542,6 +550,38 @@ class Build extends Model
$this->setModified('extra');
}
/**
* Set the value of Extra / extra.
*
* @param $name string
* @param $value mixed
*/
public function setExtraValue($name, $value)
{
$extra = json_decode($this->data['extra'], true);
if ($extra === false) {
$extra = [];
}
$extra[$name] = $value;
$this->setExtra(json_encode($extra));
}
/**
* Set the values of Extra / extra.
*
* @param $name string
* @param $values mixed
*/
public function setExtraValues($values)
{
$extra = json_decode($this->data['extra'], true);
if ($extra === false) {
$extra = [];
}
$extra = array_replace($extra, $values);
$this->setExtra(json_encode($extra));
}
/**
* Get the Project model for this Build by Id.
*
@ -931,6 +971,36 @@ class Build extends Model
return false;
}
/**
* Get the value of Environment / environment.
*
* @return string
*/
public function getEnvironment()
{
$rtn = $this->data['environment'];
return $rtn;
}
/**
* Set the value of Environment / environment.
*
* @param $value string
*/
public function setEnvironment($value)
{
$this->validateString('Environment', $value);
if ($this->data['environment'] === $value) {
return;
}
$this->data['environment'] = $value;
$this->setModified('environment');
}
/**
* Create an SSH key file on disk for this build.
*

View file

@ -4,6 +4,7 @@ namespace PHPCensor\Model\Build;
use PHPCensor\Model\Build;
use PHPCensor\Builder;
use Psr\Log\LogLevel;
/**
* Remote Git Build Model
@ -33,6 +34,10 @@ class RemoteGitBuild extends Build
$success = $this->cloneByHttp($builder, $buildPath);
}
if ($success) {
$success = $this->mergeBranches($builder, $buildPath);
}
if (!$success) {
$builder->logFailure('Failed to clone remote git repository.');
return false;
@ -41,6 +46,28 @@ class RemoteGitBuild extends Build
return $this->handleConfig($builder, $buildPath);
}
/**
* @param Builder $builder
* @param string $buildPath
* @return bool
*/
protected function mergeBranches(Builder $builder, $buildPath)
{
$branches = $this->getExtra('branches');
if (!empty($branches)) {
$cmd = 'cd "%s" && git merge --quiet origin/%s';
foreach ($branches as $branch) {
$success = $builder->executeCommand($cmd, $buildPath, $branch);
if (!$success) {
$builder->log('Fail merge branch origin/'.$branch, LogLevel::ERROR);
return false;
}
$builder->log('Merged branch origin/'.$branch, LogLevel::INFO);
}
}
return true;
}
/**
* Use an HTTP-based git clone.
*/

View file

@ -0,0 +1,233 @@
<?php
namespace PHPCensor\Model;
use PHPCensor\Model;
class Environment extends Model
{
/**
* @var array
*/
public static $sleepable = [];
/**
* @var string
*/
protected $tableName = 'environment';
/**
* @var string
*/
protected $modelName = 'Environment';
/**
* @var array
*/
protected $data = [
'id' => null,
'project_id' => null,
'name' => null,
'branches' => null,
];
/**
* @var array
*/
protected $getters = [
// Direct property getters:
'id' => 'getId',
'project_id' => 'getProjectId',
'name' => 'getName',
'branches' => 'getBranches',
// Foreign key getters:
];
/**
* @var array
*/
protected $setters = [
// Direct property setters:
'id' => 'setId',
'project_id' => 'setProjectId',
'name' => 'setName',
'branches' => 'setBranches',
// Foreign key setters:
];
/**
* @var array
*/
public $columns = [
'id' => [
'type' => 'int',
'length' => 11,
'primary_key' => true,
'auto_increment' => true,
'default' => null,
],
'project_id' => [
'type' => 'int',
'length' => 11,
'primary_key' => true,
'default' => null,
],
'name' => [
'type' => 'varchar',
'length' => 20,
'default' => null,
],
'branches' => [
'type' => 'text',
'default' => '',
],
];
/**
* @var array
*/
public $indexes = [
'PRIMARY' => ['unique' => true, 'columns' => 'project_id, name'],
];
/**
* @var array
*/
public $foreignKeys = [
'environment_ibfk_1' => [
'local_col' => 'project_id',
'update' => 'CASCADE',
'delete' => '',
'table' => 'project',
'col' => 'id'
],
];
/**
* Get the value of Id / id.
*
* @return int
*/
public function getId()
{
$rtn = $this->data['id'];
return $rtn;
}
/**
* Get the value of Id / id.
*
* @return int
*/
public function getProjectId()
{
$rtn = $this->data['project_id'];
return $rtn;
}
/**
* Get the value of Title / title.
*
* @return string
*/
public function getName()
{
$rtn = $this->data['name'];
return $rtn;
}
/**
* Get the value of Title / title.
*
* @return string
*/
public function getBranches()
{
$rtn = array_filter(array_map('trim', explode("\n", $this->data['branches'])));
return $rtn;
}
/**
* Set the value of Id / id.
*
* Must not be null.
* @param $value int
*/
public function setId($value)
{
$this->validateNotNull('Id', $value);
$this->validateInt('Id', $value);
if ($this->data['id'] === $value) {
return;
}
$this->data['id'] = $value;
$this->setModified('id');
}
/**
* Set the value of Id / id.
*
* Must not be null.
* @param $value int
*/
public function setProjectId($value)
{
$this->validateNotNull('ProjectId', $value);
$this->validateInt('ProjectId', $value);
if ($this->data['project_id'] === $value) {
return;
}
$this->data['project_id'] = $value;
$this->setModified('project_id');
}
/**
* Set the value of Name / name
*
* Must not be null.
* @param $value string
*/
public function setName($value)
{
$this->validateNotNull('Name', $value);
$this->validateString('Name', $value);
if ($this->data['name'] === $value) {
return;
}
$this->data['name'] = $value;
$this->setModified('name');
}
/**
* Set the value of Branches / branches
*
* Must not be null.
* @param $value array
*/
public function setBranches($value)
{
$this->validateNotNull('Branches', $value);
$value = implode("\n", $value);
if ($this->data['branches'] === $value) {
return;
}
$this->data['branches'] = $value;
$this->setModified('branches');
}
}

View file

@ -5,6 +5,9 @@ namespace PHPCensor\Model;
use PHPCensor\Model;
use b8\Store;
use b8\Store\Factory;
use PHPCensor\Store\EnvironmentStore;
use Symfony\Component\Yaml\Parser as YamlParser;
use Symfony\Component\Yaml\Dumper as YamlDumper;
/**
* @author Dan Cryer <dan@block8.co.uk>
@ -767,4 +770,135 @@ class Project extends Model
return $icon;
}
/**
* Get Environments
*
* @return array contain items with \PHPCensor\Model\Environment
*/
public function getEnvironmentsObjects()
{
$key = $this->getId();
if (empty($key)) {
return null;
}
$cacheKey = 'Cache.ProjectEnvironments.' . $key;
$rtn = $this->cache->get($cacheKey, null);
if (empty($rtn)) {
/** @var EnvironmentStore $store */
$store = Factory::getStore('Environment', 'PHPCensor');
$rtn = $store->getByProjectId($key);
$this->cache->set($cacheKey, $rtn);
}
return $rtn;
}
/**
* Get Environments
*
* @return string[]
*/
public function getEnvironmentsNames()
{
$environments = $this->getEnvironmentsObjects();
$environments_names = [];
foreach($environments['items'] as $environment) {
/** @var Environment $environment */
$environments_names[] = $environment->getName();
}
return $environments_names;
}
/**
* Get Environments
*
* @return string yaml
*/
public function getEnvironments()
{
$environments = $this->getEnvironmentsObjects();
$environments_config = [];
foreach($environments['items'] as $environment) {
/** @var Environment $environment */
$environments_config[$environment->getName()] = $environment->getBranches();
}
$yaml_dumper = new YamlDumper();
$value = $yaml_dumper->dump($environments_config, 10, 0, true, false);
return $value;
}
/**
* Set Environments
*
* @param string $value yaml
*/
public function setEnvironments($value)
{
$yaml_parser = new YamlParser();
$environments_config = $yaml_parser->parse($value);
$environments_names = !empty($environments_config) ? array_keys($environments_config) : [];
$current_environments = $this->getEnvironmentsObjects();
$store = Factory::getStore('Environment', 'PHPCensor');
foreach ($current_environments['items'] as $environment) {
/** @var Environment $environment */
$key = array_search($environment->getName(), $environments_names);
if ($key !== false) {
// already exist
unset($environments_names[$key]);
$environment->setBranches(!empty($environments_config[$environment->getName()]) ? $environments_config[$environment->getName()] : []);
} else {
// remove
$store->delete($environment);
}
}
if (!empty($environments_names)) {
// add
foreach ($environments_names as $environment_name) {
$environment = new Environment();
$environment->setProjectId($this->getId());
$environment->setName($environment_name);
$environment->setBranches(!empty($environments_config[$environment->getName()]) ? $environments_config[$environment->getName()] : []);
$store->save($environment);
}
}
}
/**
* @param string $branch
* @return string[]
*/
public function getEnvironmentsNamesByBranch($branch)
{
$environments_names = [];
$environments = $this->getEnvironmentsObjects();
foreach($environments['items'] as $environment) {
/** @var Environment $environment */
if (in_array($branch, $environment->getBranches())) {
$environments_names[] = $environment->getName();
}
}
return $environments_names;
}
/**
* @param string $environment_name
* @return string[]
*/
public function getBranchesByEnvironment($environment_name)
{
$branches = [];
$environments = $this->getEnvironmentsObjects();
foreach($environments['items'] as $environment) {
/** @var Environment $environment */
if ($environment_name == $environment->getName()) {
return $environment->getBranches();
}
}
return $branches;
}
}

View file

@ -35,6 +35,7 @@ class BuildService
/**
* @param Project $project
* @param string $environment
* @param string|null $commitId
* @param string|null $branch
* @param string|null $committerEmail
@ -44,6 +45,7 @@ class BuildService
*/
public function createBuild(
Project $project,
$environment,
$commitId = null,
$branch = null,
$committerEmail = null,
@ -54,6 +56,10 @@ class BuildService
$build->setCreated(new \DateTime());
$build->setProject($project);
$build->setStatus(0);
$build->setEnvironment($environment);
$branches = $project->getBranchesByEnvironment($environment);
$build->setExtraValue('branches', $branches);
if (!is_null($commitId)) {
$build->setCommitId($commitId);
@ -77,7 +83,7 @@ class BuildService
}
if (!is_null($extra)) {
$build->setExtra(json_encode($extra));
$build->setExtraValues($extra);
}
$build = $this->buildStore->save($build);

View file

@ -84,6 +84,10 @@ class ProjectService
$project->setGroup($options['group']);
}
if (array_key_exists('environments', $options)) {
$project->setEnvironments($options['environments']);
}
// Allow certain project types to set access information:
$this->processAccessInformation($project);

View file

@ -0,0 +1,89 @@
<?php
namespace PHPCensor\Store;
use b8\Database;
use PHPCensor\Model\Environment;
use PHPCensor\Store;
use b8\Exception\HttpException;
class EnvironmentStore extends Store
{
protected $tableName = 'environment';
protected $modelName = '\PHPCensor\Model\Environment';
protected $primaryKey = 'id';
/**
* Get a Environment by primary key (Id)
* @param int $value
* @param string $useConnection
* @return null|Environment
*/
public function getByPrimaryKey($value, $useConnection = 'read')
{
return $this->getById($value, $useConnection);
}
/**
* Get a single Environment by Id.
* @param $value
* @param string $useConnection
* @return null|Environment
* @throws HttpException
*/
public function getById($value, $useConnection = 'read')
{
if (is_null($value)) {
throw new HttpException('Value passed to ' . __FUNCTION__ . ' cannot be null.');
}
$query = 'SELECT * FROM {{environment}} WHERE {{id}} = :id LIMIT 1';
$stmt = Database::getConnection($useConnection)->prepareCommon($query);
$stmt->bindValue(':id', $value);
if ($stmt->execute()) {
if ($data = $stmt->fetch(\PDO::FETCH_ASSOC)) {
return new Environment($data);
}
}
return null;
}
/**
* Get multiple Environment by Project id.
*
* @param integer $value
* @param string $useConnection
*
* @return array
*
* @throws \Exception
*/
public function getByProjectId($value, $useConnection = 'read')
{
if (is_null($value)) {
throw new \Exception('Value passed to ' . __FUNCTION__ . ' cannot be null.');
}
$query = 'SELECT * FROM {{environment}} WHERE {{project_id}} = :project_id';
$stmt = Database::getConnection($useConnection)->prepareCommon($query);
$stmt->bindValue(':project_id', $value);
if ($stmt->execute()) {
$res = $stmt->fetchAll(\PDO::FETCH_ASSOC);
$map = function ($item) {
return new Environment($item);
};
$rtn = array_map($map, $res);
$count = count($rtn);
return ['items' => $rtn, 'count' => $count];
} else {
return ['items' => [], 'count' => 0];
}
}
}

View file

@ -22,18 +22,26 @@
</tr>
<tr>
<th><?php Lang::out('branch'); ?></th>
<th><?php Lang::out('environment'); ?></th>
<td style="text-align: right">
<a target="_blank" href="<?php print $build->getBranchLink(); ?>">
<span class="label label-default"><?php print $build->getBranch(); ?></span>
</a>
<span class="label label-default"><?php print $build->getEnvironment(); ?></span>
</td>
</tr>
<tr>
<th><?php Lang::out('duration'); ?></th>
<td style="text-align: right" class="build-duration duration">
<?php print $build->getDuration(); ?> <?= Lang::get('seconds'); ?>
<th><?php Lang::out('merged_branches'); ?></th>
<td style="text-align: right">
<span class="label label-default"><?php print $build->getBranch() ?></span>
+ <?php
$branches = $build->getExtra('branches');
if (!empty($branches)) {
foreach($branches as $branch) {
?><span class="label label-default"><?php print $branch ?></span><?php
}
} else {
?>&mdash;<?php
}
?>
</td>
</tr>
</table>
@ -51,6 +59,15 @@
<div class="box-body no-padding">
<table class="table">
<tr>
<th><?php Lang::out('branch'); ?></th>
<td style="text-align: right">
<a target="_blank" href="<?php print $build->getBranchLink(); ?>">
<span class="label label-default"><?php print $build->getBranch(); ?></span>
</a>
</td>
</tr>
<tr>
<th><?php Lang::out('commit'); ?></th>
<td style="text-align: right">
@ -107,6 +124,13 @@
<?php print $build->getFinished() ? $build->getFinished()->format('Y-m-d H:i:s') : ''; ?>
</td>
</tr>
<tr>
<th><?php Lang::out('duration'); ?></th>
<td style="text-align: right" class="build-duration duration">
<?php print $build->getDuration(); ?> <?= Lang::get('seconds'); ?>
</td>
</tr>
</table>
</div>
</div>

View file

@ -4,6 +4,9 @@
<?php
foreach ($builds as $build):
$environment = $build->getEnvironment();
$branches = $build->getExtra('branches');
switch ($build->getStatus()) {
case \PHPCensor\Model\Build::STATUS_PENDING:
$updated = $build->getCreated();
@ -60,6 +63,7 @@
<a href="<?php print APP_URL; ?>project/view/<?php print $build->getProjectId(); ?>">
<?php print $build->getProject()->getTitle(); ?>
</a>
<span><?php print $environment; ?></span>
-
<a href="<?php print APP_URL; ?>build/view/<?php print $build->getId(); ?>">
Build #<?php print $build->getId(); ?>
@ -69,7 +73,8 @@
</h3>
<div class="timeline-body">
<a href="<?php echo $build->getBranchLink();?>"><?php echo $build->getProject()->getBranch(); ?></a> -
<a href="<?php echo $build->getBranchLink();?>"><?php echo $build->getProject()->getBranch(); ?></a>
<?php print $branches ? ' + '.implode(', ', $branches) : ''; ?> -
<?php
if ($build->getCommitId() !== 'Manual') {
print sprintf(

View file

@ -30,6 +30,9 @@
<?php
foreach ($builds as $build):
$environment = $build->getEnvironment();
$branches = $build->getExtra('branches');
switch ($build->getStatus()) {
case \PHPCensor\Model\Build::STATUS_PENDING:
$updated = $build->getCreated();
@ -86,6 +89,7 @@
<a href="<?php print APP_URL; ?>project/view/<?php print $build->getProjectId(); ?>">
<?php print $build->getProject()->getTitle(); ?>
</a>
<span><?php print $environment; ?></span>
-
<a href="<?php print APP_URL; ?>build/view/<?php print $build->getId(); ?>">
Build #<?php print $build->getId(); ?>
@ -95,7 +99,8 @@
</h3>
<div class="timeline-body">
<a href="<?php echo $build->getBranchLink();?>"><?php echo $build->getProject()->getBranch(); ?></a> -
<a href="<?php echo $build->getBranchLink();?>"><?php echo $build->getProject()->getBranch(); ?></a>
<?php print $branches ? ' + '.implode(', ', $branches) : ''; ?> -
<?php
if ($build->getCommitId() !== 'Manual') {
print sprintf(

View file

@ -36,6 +36,8 @@ switch($build->getStatus())
$status = Lang::get('failed');
break;
}
$branches = $build->getExtra('branches');
?>
<tr>
<td><a href="<?php echo APP_URL ?>build/view/<?php print $build->getId(); ?>">#<?php print str_pad($build->getId(), 6, '0', STR_PAD_LEFT); ?></a></td>
@ -55,7 +57,11 @@ switch($build->getStatus())
?>
</td>
<td><a href="<?php print $build->getBranchLink(); ?>" target="_blank"><?php print $build->getBranch(); ?></a></td>
<td><?php print $build->getEnvironment(); ?></td>
<td>
<a href="<?php print $build->getBranchLink(); ?>" target="_blank"><?php print $build->getBranch(); ?></a>
<?php print $branches ? ' + '.implode(', ', $branches) : ''; ?>
</td>
<td>
<span class='label label-<?php echo $subcls ?>'><?php echo $status ?></span>
</td>

View file

@ -8,6 +8,11 @@
lineWrapping: true,
lineNumbers: true
});
CodeMirror.fromTextArea(document.getElementById('element-environments'), {
mode: "yaml",
lineWrapping: true,
lineNumbers: true
});
setupProjectForm();
});

View file

@ -1,6 +1,7 @@
<?php use PHPCensor\Helper\Lang; ?>
<script>
var PROJECT_ID = <?php print $project->getId(); ?>;
var PROJECT_ENVIRONMENT = '<?php print $environment; ?>';
var PROJECT_BRANCH = '<?php print $branch; ?>';
var PER_PAGE = <?php print $perPage; ?>;
</script>
@ -17,32 +18,97 @@
<div class="pull-right btn-group">
<?php if (!$project->getArchived()): ?>
<?php if($this->User()->getIsAdmin()): ?>
<a class="btn btn-danger" href="<?= APP_URL . 'project/build/' . $project->getId(); ?><?= !empty($branch) ? '/' . urlencode($branch) : '' ?>?debug=1">
<?php Lang::out('build_now_debug'); ?>
</a>
<div class="btn-group build-btn">
<button type="button" class="btn btn-danger dropdown-toggle" data-toggle="dropdown">
<?php Lang::out('build_now_debug'); ?>&nbsp;&nbsp;<span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu">
<?php if(!empty($environments)): ?>
<?php foreach ($environments as $curenvironment) : ?>
<li <?php echo ($curenvironment == $environment) ? 'class="active"' : ''?>>
<a href="<?php echo APP_URL ?>project/build/<?php print $project->getId(); ?>/environment/<?php echo urlencode($curenvironment) ?>?debug=1">
<i class="fa fa-cog"></i><?php echo $curenvironment ?>
</a>
</li>
<?php endforeach; ?>
<li class="divider"></li>
<?php endif; ?>
<?php foreach ($branches as $curbranch) : ?>
<li <?php echo ($curbranch == $branch) ? 'class="active"' : ''?>>
<a href="<?php echo APP_URL ?>project/build/<?php print $project->getId(); ?>/branch/<?php echo urlencode($curbranch) ?>">
<i class="fa fa-code-fork"></i><?php echo $curbranch ?>
</a>
</li>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
<a class="btn btn-success" href="<?= APP_URL . 'project/build/' . $project->getId(); ?><?= !empty($branch) ? '/' . urlencode($branch) : '' ?>">
<?php Lang::out('build_now'); ?>
</a>
<div class="btn-group build-btn">
<button type="button" class="btn btn-success dropdown-toggle" data-toggle="dropdown">
<?php Lang::out('build_now'); ?>&nbsp;&nbsp;<span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu">
<?php if(!empty($environments)): ?>
<?php foreach ($environments as $curenvironment) : ?>
<li <?php echo ($curenvironment == $environment) ? 'class="active"' : ''?>>
<a href="<?php echo APP_URL ?>project/build/<?php print $project->getId(); ?>/environment/<?php echo urlencode($curenvironment) ?>">
<i class="fa fa-cog"></i><?php echo $curenvironment ?>
</a>
</li>
<?php endforeach; ?>
<li class="divider"></li>
<?php endif; ?>
<?php foreach ($branches as $curbranch) : ?>
<li <?php echo ($curbranch == $branch) ? 'class="active"' : ''?>>
<a href="<?php echo APP_URL ?>project/build/<?php print $project->getId(); ?>/branch/<?php echo urlencode($curbranch) ?>">
<i class="fa fa-code-fork"></i><?php echo $curbranch ?>
</a>
</li>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
<div class="btn-group branch-btn pull-right">
<div class="btn-group environment-btn pull-right">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
<?php print !empty($branch) ? Lang::get('branch_x', $branch) : Lang::get('branch'); ?>&nbsp;&nbsp;<span class="caret"></span>
<?php
if (!empty($environment)) {
print Lang::get('environment_x', $environment);
} elseif (!empty($branch)) {
print Lang::get('branch_x', $branch);
} else {
print Lang::get('All');
}
?>&nbsp;&nbsp;<span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu">
<li><a href="<?php echo APP_URL ?>project/view/<?php print $project->getId(); ?>"><?php Lang::out('all'); ?></a></li>
<li class="divider"></li>
<?php if(!empty($environments)): ?>
<?php foreach ($environments as $curenvironment) : ?>
<li <?php echo ($curenvironment == $environment) ? 'class="active"' : ''?>>
<a href="<?php echo APP_URL ?>project/view/<?php print $project->getId(); ?>?environment=<?php echo urlencode($curenvironment) ?>">
<i class="fa fa-cog"></i><?php echo $curenvironment ?>
</a>
</li>
<?php endforeach; ?>
<li class="divider"></li>
<?php endif; ?>
<?php foreach ($branches as $curbranch) : ?>
<li <?php echo ($curbranch == $branch) ? 'class="active"' : ''?>>
<a href="<?php echo APP_URL ?>project/view/<?php print $project->getId(); ?>?branch=<?php echo urlencode($curbranch) ?>">
<?php echo $curbranch ?>
<i class="fa fa-code-fork"></i><?php echo $curbranch ?>
</a>
</li>
<?php endforeach; ?>
<li class="divider"></li>
<li><a href="<?php echo APP_URL ?>project/view/<?php print $project->getId(); ?>"><?php Lang::out('all_branches'); ?></a></li>
</ul>
</div>
</div>
@ -61,6 +127,7 @@
<th><?php Lang::out('id'); ?></th>
<th><?php Lang::out('date'); ?></th>
<th class="hidden-md hidden-sm hidden-xs"><?php Lang::out('commit'); ?></th>
<th><?php Lang::out('environment'); ?></th>
<th><?php Lang::out('branch'); ?></th>
<th><?php Lang::out('status'); ?></th>
<th><?php Lang::out('duration'); ?></th>

View file

@ -40,7 +40,7 @@ class BuildServiceTest extends \PHPUnit_Framework_TestCase
$project->setType('github');
$project->setId(101);
$returnValue = $this->testedService->createBuild($project);
$returnValue = $this->testedService->createBuild($project, null);
$this->assertEquals(101, $returnValue->getProjectId());
$this->assertEquals(Build::STATUS_PENDING, $returnValue->getStatus());
@ -61,7 +61,7 @@ class BuildServiceTest extends \PHPUnit_Framework_TestCase
$project->setType('hg');
$project->setId(101);
$returnValue = $this->testedService->createBuild($project, '123', 'testbranch', 'test@example.com', 'test');
$returnValue = $this->testedService->createBuild($project, null, '123', 'testbranch', 'test@example.com', 'test');
$this->assertEquals('testbranch', $returnValue->getBranch());
$this->assertEquals('123', $returnValue->getCommitId());
@ -75,7 +75,7 @@ class BuildServiceTest extends \PHPUnit_Framework_TestCase
$project->setType('bitbucket');
$project->setId(101);
$returnValue = $this->testedService->createBuild($project, null, null, null, null, ['item1' => 1001]);
$returnValue = $this->testedService->createBuild($project, null, null, null, null, null, ['item1' => 1001]);
$this->assertEquals(1001, $returnValue->getExtra('item1'));
}