diff --git a/src/PHPCensor/Command/CreateBuildCommand.php b/src/PHPCensor/Command/CreateBuildCommand.php index 027fded1..29eab6be 100644 --- a/src/PHPCensor/Command/CreateBuildCommand.php +++ b/src/PHPCensor/Command/CreateBuildCommand.php @@ -57,9 +57,9 @@ class CreateBuildCommand extends Command */ public function execute(InputInterface $input, OutputInterface $output) { - $projectId = $input->getArgument('projectId'); - $commitId = $input->getOption('commit'); - $branch = $input->getOption('branch'); + $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); diff --git a/src/PHPCensor/Controller/ProjectController.php b/src/PHPCensor/Controller/ProjectController.php index d2d82874..8f77e26b 100644 --- a/src/PHPCensor/Controller/ProjectController.php +++ b/src/PHPCensor/Controller/ProjectController.php @@ -94,10 +94,12 @@ class ProjectController extends PHPCensor\Controller $this->view->perPage = $perPage; $this->layout->title = $project->getTitle(); + + $this->layout->subtitle = ''; if (!empty($this->view->environment)) { - $this->layout->subtitle = $this->view->environment; - } else { - $this->layout->subtitle = $this->view->branch; + $this->layout->subtitle = ' ' . $this->view->environment; + } elseif (!empty($this->view->branch)) { + $this->layout->subtitle = ' ' . $this->view->branch; } return $this->view->render(); @@ -148,7 +150,16 @@ class ProjectController extends PHPCensor\Controller } $email = $_SESSION['php-censor-user']->getEmail(); - $build = $this->buildService->createBuild($project, $environment, null, urldecode($branch), $email, null, $extra); + $build = $this->buildService->createBuild( + $project, + $environment, + null, + urldecode($branch), + null, + $email, + null, + $extra + ); if ($this->buildService->queueError) { $_SESSION['global_error'] = Lang::get('add_to_queue_failed'); diff --git a/src/PHPCensor/Controller/WebhookController.php b/src/PHPCensor/Controller/WebhookController.php index 98293057..001af4cb 100644 --- a/src/PHPCensor/Controller/WebhookController.php +++ b/src/PHPCensor/Controller/WebhookController.php @@ -121,6 +121,7 @@ class WebhookController extends Controller $project, $commit['new']['target']['hash'], $commit['new']['name'], + null, $email, $commit['new']['target']['message'] ); @@ -152,6 +153,7 @@ class WebhookController extends Controller $project, $commit['raw_node'], $commit['branch'], + null, $email, $commit['message'] ); @@ -179,7 +181,7 @@ class WebhookController extends Controller $commitMessage = $this->getParam('message'); $committer = $this->getParam('committer'); - return $this->createBuild($project, $commit, $branch, $committer, $commitMessage); + return $this->createBuild($project, $commit, $branch, null, $committer, $commitMessage); } /** @@ -197,16 +199,20 @@ class WebhookController extends Controller $payload = json_decode($this->getParam('payload'), true); break; default: - return ['status' => 'failed', 'error' => 'Content type not supported.', 'responseCode' => 401]; + return [ + 'status' => 'failed', + 'error' => 'Content type not supported.', + 'responseCode' => 401 + ]; } - // Handle Pull Request web hooks: + // Handle Pull Request webhooks: if (array_key_exists('pull_request', $payload)) { return $this->githubPullRequest($project, $payload); } - // Handle Push web hooks: - if (array_key_exists('commits', $payload)) { + // Handle Push (and Tag) webhooks: + if (array_key_exists('head_commit', $payload)) { return $this->githubCommitRequest($project, $payload); } @@ -223,47 +229,50 @@ class WebhookController extends Controller */ protected function githubCommitRequest(Project $project, array $payload) { - // Github sends a payload when you close a pull request with a - // non-existent commit. We don't want this. - if (array_key_exists('after', $payload) && $payload['after'] === '0000000000000000000000000000000000000000') { + // Github sends a payload when you close a pull request with a non-existent commit. We don't want this. + if ( + array_key_exists('after', $payload) && + $payload['after'] === '0000000000000000000000000000000000000000' + ) { return ['status' => 'ignored']; } - if (isset($payload['commits']) && is_array($payload['commits'])) { - // If we have a list of commits, then add them all as builds to be tested: - + if (isset($payload['head_commit']) && $payload['head_commit']) { + $isTag = (substr($payload['ref'], 0, 10) == 'refs/tags/') ? true : false; + $commit = $payload['head_commit']; $results = []; $status = 'failed'; - foreach ($payload['commits'] as $commit) { - if (!$commit['distinct']) { - $results[$commit['id']] = ['status' => 'ignored']; - continue; - } - + + if (!$commit['distinct']) { + $results[$commit['id']] = ['status' => 'ignored']; + } else { try { - $branch = str_replace('refs/heads/', '', $payload['ref']); - $committer = $commit['committer']['email']; + $tag = null; + if ($isTag) { + $tag = str_replace('refs/tags/', '', $payload['ref']); + $branch = str_replace('refs/heads/', '', $payload['base_ref']); + $committer = $payload['pusher']['email']; + } else { + $branch = str_replace('refs/heads/', '', $payload['ref']); + $committer = $commit['committer']['email']; + } + $results[$commit['id']] = $this->createBuild( $project, $commit['id'], $branch, + $tag, $committer, $commit['message'] ); + $status = 'ok'; } catch (Exception $ex) { $results[$commit['id']] = ['status' => 'failed', 'error' => $ex->getMessage()]; } } - return ['status' => $status, 'commits' => $results]; - } - if (substr($payload['ref'], 0, 10) == 'refs/tags/') { - // If we don't, but we're dealing with a tag, add that instead: - $branch = str_replace('refs/tags/', 'Tag: ', $payload['ref']); - $committer = $payload['pusher']['email']; - $message = $payload['head_commit']['message']; - return $this->createBuild($project, $payload['after'], $branch, $committer, $message); + return ['status' => $status, 'commits' => $results]; } return ['status' => 'ignored', 'message' => 'Unusable payload.']; @@ -335,7 +344,7 @@ class WebhookController extends Controller 'remote_url' => $payload['pull_request']['head']['repo'][$remoteUrlKey], ]; - $results[$id] = $this->createBuild($project, $id, $branch, $committer, $message, $extra); + $results[$id] = $this->createBuild($project, $id, $branch, null, $committer, $message, $extra); $status = 'ok'; } catch (Exception $ex) { $results[$id] = ['status' => 'failed', 'error' => $ex->getMessage()]; @@ -363,7 +372,7 @@ class WebhookController extends Controller $commit = $attributes['last_commit']; $committer = $commit['author']['email']; - return $this->createBuild($project, $commit['id'], $branch, $committer, $commit['message']); + return $this->createBuild($project, $commit['id'], $branch, null, $committer, $commit['message']); } } @@ -381,6 +390,7 @@ class WebhookController extends Controller $project, $commit['id'], $branch, + null, $committer, $commit['message'] ); @@ -413,7 +423,7 @@ class WebhookController extends Controller $commitMessage = $this->getParam('message'); $committer = $this->getParam('committer'); - return $this->createBuild($project, $commit, $branch, $committer, $commitMessage); + return $this->createBuild($project, $commit, $branch, null, $committer, $commitMessage); } /** @@ -467,6 +477,7 @@ class WebhookController extends Controller $project, $commit['id'], $branch, + null, $committer, $commit['message'] ); @@ -486,11 +497,12 @@ class WebhookController extends Controller * Wrapper for creating a new build. * * @param Project $project - * @param string $commitId - * @param string $branch - * @param string $committer - * @param string $commitMessage - * @param array $extra + * @param string $commitId + * @param string $branch + * @param string $tag + * @param string $committer + * @param string $commitMessage + * @param array $extra * * @return array * @@ -500,6 +512,7 @@ class WebhookController extends Controller Project $project, $commitId, $branch, + $tag, $committer, $commitMessage, array $extra = null @@ -512,28 +525,43 @@ class WebhookController extends Controller $builds = $this->buildStore->getByProjectAndCommit($project->getId(), $commitId); $ignore_environments = []; + $ignore_tags = []; if ($builds['count']) { foreach($builds['items'] as $build) { /** @var Build $build */ $ignore_environments[$build->getId()] = $build->getEnvironment(); + $ignore_tags[$build->getId()] = $build->getTag(); } } $environments = $project->getEnvironmentsObjects(); if ($environments['count']) { - $created_builds = []; + $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 ( + !in_array($environment_name, $ignore_environments) || + ($tag && !in_array($tag, $ignore_tags, true)) + ) { // 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, + $build = $this->buildService->createBuild( + $project, + $environment_name, + $commitId, + $project->getBranch(), + $tag, + $committer, + $commitMessage, + $extra ); + + $created_builds[] = [ + 'id' => $build->getID(), + 'environment' => $environment_name, + ]; } else { $duplicates[] = array_search($environment_name, $ignore_environments); } @@ -552,8 +580,21 @@ class WebhookController extends Controller } } else { $environment_name = null; - if (!in_array($environment_name, $ignore_environments)) { - $build = $this->buildService->createBuild($project, null, $commitId, $branch, $committer, $commitMessage, $extra); + if ( + !in_array($environment_name, $ignore_environments, true) || + ($tag && !in_array($tag, $ignore_tags, true)) + ) { + $build = $this->buildService->createBuild( + $project, + null, + $commitId, + $branch, + $tag, + $committer, + $commitMessage, + $extra + ); + return ['status' => 'ok', 'buildID' => $build->getID()]; } else { return [ diff --git a/src/PHPCensor/Migrations/20170420142131_added_tag_column_to_build_table.php b/src/PHPCensor/Migrations/20170420142131_added_tag_column_to_build_table.php new file mode 100644 index 00000000..cc5f80e5 --- /dev/null +++ b/src/PHPCensor/Migrations/20170420142131_added_tag_column_to_build_table.php @@ -0,0 +1,24 @@ +table('build'); + + if (!$table->hasColumn('tag')) { + $table->addColumn('tag', 'string', ['limit' => 250, 'null' => true])->save(); + } + } + + public function down() + { + $table = $this->table('build'); + + if ($table->hasColumn('tag')) { + $table->removeColumn('tag')->save(); + } + } +} diff --git a/src/PHPCensor/Model/Build.php b/src/PHPCensor/Model/Build.php index a4b6aced..de502d72 100644 --- a/src/PHPCensor/Model/Build.php +++ b/src/PHPCensor/Model/Build.php @@ -51,6 +51,7 @@ class Build extends Model 'status' => null, 'log' => null, 'branch' => null, + 'tag' => null, 'created' => null, 'started' => null, 'finished' => null, @@ -71,6 +72,7 @@ class Build extends Model 'status' => 'getStatus', 'log' => 'getLog', 'branch' => 'getBranch', + 'tag' => 'getTag', 'created' => 'getCreated', 'started' => 'getStarted', 'finished' => 'getFinished', @@ -94,6 +96,7 @@ class Build extends Model 'status' => 'setStatus', 'log' => 'setLog', 'branch' => 'setBranch', + 'setTag' => 'setTag', 'created' => 'setCreated', 'started' => 'setStarted', 'finished' => 'setFinished', @@ -142,6 +145,11 @@ class Build extends Model 'length' => 250, 'default' => 'master', ], + 'tag' => [ + 'type' => 'varchar', + 'length' => 250, + 'default' => null, + ], 'created' => [ 'type' => 'datetime', 'nullable' => true, @@ -712,6 +720,14 @@ class Build extends Model return '#'; } + /** + * Get link to tag from another source (i.e. Github) + */ + public function getTagLink() + { + return '#'; + } + /** * Return a template to use to generate a link to a specific file. * @@ -986,6 +1002,36 @@ class Build extends Model return false; } + /** + * Get the value of Tag / tag. + * + * @return string + */ + public function getTag() + { + $rtn = $this->data['tag']; + + return $rtn; + } + + /** + * Set the value of Tag / tag. + * + * @param $value string + */ + public function setTag($value) + { + $this->validateString('Tag', $value); + + if ($this->data['tag'] === $value) { + return; + } + + $this->data['tag'] = $value; + + $this->setModified('tag'); + } + /** * Get the value of Environment / environment. * diff --git a/src/PHPCensor/Model/Build/GithubBuild.php b/src/PHPCensor/Model/Build/GithubBuild.php index c2847269..61694ee1 100644 --- a/src/PHPCensor/Model/Build/GithubBuild.php +++ b/src/PHPCensor/Model/Build/GithubBuild.php @@ -32,6 +32,14 @@ class GithubBuild extends RemoteGitBuild return 'https://github.com/' . $this->getProject()->getReference() . '/tree/' . $this->getBranch(); } + /** + * Get link to tag from another source (i.e. Github) + */ + public function getTagLink() + { + return 'https://github.com/' . $this->getProject()->getReference() . '/tree/' . $this->getTag(); + } + /** * Send status updates to any relevant third parties (i.e. Github) */ diff --git a/src/PHPCensor/Service/BuildService.php b/src/PHPCensor/Service/BuildService.php index 89ac4f15..5e789cc6 100644 --- a/src/PHPCensor/Service/BuildService.php +++ b/src/PHPCensor/Service/BuildService.php @@ -38,6 +38,7 @@ class BuildService * @param string $environment * @param string|null $commitId * @param string|null $branch + * @param string|null $tag * @param string|null $committerEmail * @param string|null $commitMessage * @param string|null $extra @@ -49,6 +50,7 @@ class BuildService $environment, $commitId = null, $branch = null, + $tag = null, $committerEmail = null, $commitMessage = null, $extra = null @@ -75,6 +77,10 @@ class BuildService $build->setBranch($project->getBranch()); } + if (!is_null($tag)) { + $build->setTag($tag); + } + if (!is_null($committerEmail)) { $build->setCommitterEmail($committerEmail); } diff --git a/src/PHPCensor/Store/BuildStore.php b/src/PHPCensor/Store/BuildStore.php index 793d9a5f..9c1e1751 100644 --- a/src/PHPCensor/Store/BuildStore.php +++ b/src/PHPCensor/Store/BuildStore.php @@ -177,14 +177,17 @@ class BuildStore extends Store /** * Return an array of builds for a given project and commit ID. - * @param $projectId - * @param $commitId + * + * @param integer $projectId + * @param string $commitId + * * @return array */ public function getByProjectAndCommit($projectId, $commitId) { $query = 'SELECT * FROM {{build}} WHERE {{project_id}} = :project_id AND {{commit_id}} = :commit_id'; - $stmt = Database::getConnection('read')->prepareCommon($query); + $stmt = Database::getConnection('read')->prepareCommon($query); + $stmt->bindValue(':project_id', $projectId); $stmt->bindValue(':commit_id', $commitId); diff --git a/src/PHPCensor/View/Build/view.phtml b/src/PHPCensor/View/Build/view.phtml index bae17ff4..9e972182 100644 --- a/src/PHPCensor/View/Build/view.phtml +++ b/src/PHPCensor/View/Build/view.phtml @@ -24,9 +24,14 @@