Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/en/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Using PHP Censor
* [Git](sources/git.md)
* [Injecting variables into messages](interpolation.md)
* [Project Status Images and Status Page](status.md)
* [Build environments](environments.md)

Plugins
-------
Expand Down
47 changes: 47 additions & 0 deletions docs/en/environments.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
Environments
============

A environment can include several branches - base branch (default project branch) and optional additional branches (which merge into base).

When you commit to a branch, builds all environments in which branch included (base branch implicitly included to all environments).

When you build a environment, additional branches merged into base branch.

For example, it can be useful when you delay merging into master or test some branches at once. Or deploy.

Config example and explanation
------------------------------
Configuration is specified on project edit page.

In this example, there are three environments:
* Production (named `pr`) is associated with the default branch for the project.
* Release candidate (`rc`) - branch by default plus branch `feature-A`
* Test (`test`) - branch by default plus branch `feature-B`

```yml
pr:
rc:
- feature-A
test:
- feature-B
```

When you push commits to `master` branch, three builds will be created - one for each of the environments.

If push commit to branch `feature-A` - build for `rc` environment will be created.

If push commit to branch `feature-C` - no build will be created.

You can use variable `%ENVIRONMENT%` in project config.

```yml
setup:
mysql:
- "DROP DATABASE IF EXISTS project_name_%ENVIRONMENT%;"
- "CREATE DATABASE project_name_%ENVIRONMENT%;"
test:
...
deploy:
mage:
env: %ENVIRONMENT%
```
2 changes: 1 addition & 1 deletion public/assets/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 2 additions & 1 deletion src/PHPCensor/Command/CreateBuildCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,15 @@ public function execute(InputInterface $input, OutputInterface $output)
$projectId = $input->getArgument('projectId');
$commitId = $input->getOption('commit');
$branch = $input->getOption('branch');
$environment = $input->hasOption('environment') ? $input->getOption('environment') : null;

$project = $this->projectStore->getById($projectId);
if (empty($project) || $project->getArchived()) {
throw new \InvalidArgumentException('Project does not exist: ' . $projectId);
}

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>');
Expand Down
44 changes: 38 additions & 6 deletions src/PHPCensor/Controller/ProjectController.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ public function init()
public function view($projectId)
{
$branch = $this->getParam('branch', '');
$environment = $this->getParam('environment', '');
$project = $this->projectStore->getById($projectId);

if (empty($project)) {
Expand All @@ -66,7 +67,7 @@ public function view($projectId)

$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) {
Expand All @@ -80,24 +81,41 @@ public function view($projectId)
$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();
}

/**
* 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();
}
Expand All @@ -115,7 +133,7 @@ public function build($projectId, $branch = '')
}

$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');
Expand Down Expand Up @@ -145,15 +163,19 @@ public function delete($projectId)
* 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;
}
Expand Down Expand Up @@ -244,6 +266,7 @@ public function add()
'allow_public_status' => $this->getParam('allow_public_status', 0),
'branch' => $this->getParam('branch', null),
'group' => $this->getParam('group_id', null),
'environments' => $this->getParam('environments', null),
];

$project = $this->projectService->createProject($title, $type, $reference, $options);
Expand Down Expand Up @@ -276,6 +299,8 @@ public function edit($projectId)
$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";
Expand Down Expand Up @@ -310,6 +335,7 @@ public function edit($projectId)
'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);
Expand Down Expand Up @@ -380,6 +406,11 @@ protected function projectForm($values, $type = 'add')
$field->setClass('form-control')->setContainerClass('form-group')->setValue('master');
$form->addField($field);

$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);

Expand Down Expand Up @@ -467,8 +498,9 @@ protected function getReferenceValidator($values)
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]);
Expand Down
57 changes: 49 additions & 8 deletions src/PHPCensor/Controller/WebhookController.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
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;
Expand Down Expand Up @@ -507,17 +508,57 @@ protected function createBuild(
// 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)),
];
}
}
}

/**
Expand Down
2 changes: 2 additions & 0 deletions src/PHPCensor/Helper/BuildInterpolator.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public function setupInterpolationVars(BaseBuild $build, $buildPath, $url)
$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();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add:

putenv('PHPCI_ENVIRONMENT=' . $this->interpolation_vars['%ENVIRONMENT%']);

$this->interpolation_vars['%PROJECT%'] = $build->getProjectId();
$this->interpolation_vars['%BUILD%'] = $build->getId();
$this->interpolation_vars['%PROJECT_TITLE%'] = $build->getProjectTitle();
Expand Down Expand Up @@ -66,6 +67,7 @@ public function setupInterpolationVars(BaseBuild $build, $buildPath, $url)
putenv('PHPCI_PROJECT_TITLE=' . $this->interpolation_vars['%PROJECT_TITLE%']);
putenv('PHPCI_BUILD_PATH=' . $this->interpolation_vars['%BUILD_PATH%']);
putenv('PHPCI_BUILD_URI=' . $this->interpolation_vars['%BUILD_URI%']);
putenv('PHPCI_ENVIRONMENT=' . $this->interpolation_vars['%ENVIRONMENT%']);
}

/**
Expand Down
5 changes: 5 additions & 0 deletions src/PHPCensor/Languages/lang.en.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
'branch_x' => 'Branch: %s',
'created_x' => 'Created: %s',
'started_x' => 'Started: %s',
'environment_x' => 'Environment: %s',

// Sidebar
'hello_name' => 'Hello, %s',
Expand Down Expand Up @@ -117,6 +118,7 @@
'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://',
Expand All @@ -127,12 +129,14 @@

// 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;',
Expand Down Expand Up @@ -194,6 +198,7 @@
'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',
Expand Down
Loading