* @package PHPCI * @subpackage Core */ class GithubBuild extends RemoteGitBuild { /** * Get link to commit from another source (i.e. Github) */ public function getCommitLink() { return 'https://github.com/' . $this->getProject()->getReference() . '/commit/' . $this->getCommitId(); } /** * Get link to branch from another source (i.e. Github) */ public function getBranchLink() { return 'https://github.com/' . $this->getProject()->getReference() . '/tree/' . $this->getBranch(); } /** * Send status updates to any relevant third parties (i.e. Github) */ public function sendStatusPostback() { $token = \b8\Config::getInstance()->get('phpci.github.token'); if (empty($token)) { return; } $project = $this->getProject(); $url = 'https://api.github.com/repos/'.$project->getReference().'/statuses/'.$this->getCommitId(); $http = new \b8\HttpClient(); switch($this->getStatus()) { case 0: case 1: $status = 'pending'; break; case 2: $status = 'success'; break; case 3: $status = 'failure'; break; default: $status = 'error'; break; } $phpciUrl = \b8\Config::getInstance()->get('phpci.url'); $params = array( 'state' => $status, 'target_url' => $phpciUrl . '/build/view/' . $this->getId()); $headers = array( 'Authorization: token ' . $token, 'Content-Type: application/x-www-form-urlencoded' ); $http->setHeaders($headers); $http->request('POST', $url, json_encode($params)); } /** * Get the URL to be used to clone this remote repository. */ protected function getCloneUrl() { $key = trim($this->getProject()->getSshPrivateKey()); if (!empty($key)) { return 'git@github.com:' . $this->getProject()->getReference() . '.git'; } else { return 'https://github.com/' . $this->getProject()->getReference() . '.git'; } } /** * Get a parsed version of the commit message, with links to issues and commits. * @return string */ public function getCommitMessage() { $rtn = parent::getCommitMessage($this->data['commit_message']); $reference = $this->getProject()->getReference(); $commitLink = '#$1'; $rtn = preg_replace('/\#([0-9]+)/', $commitLink, $rtn); $rtn = preg_replace('/\@([a-zA-Z0-9_]+)/', '@$1', $rtn); return $rtn; } /** * Get a template to use for generating links to files. * e.g. https://github.com/block8/phpci/blob/master/{FILE}#L{LINE} * @return string */ public function getFileLinkTemplate() { $reference = $this->getProject()->getReference(); $branch = $this->getBranch(); if ($this->getExtra('build_type') == 'pull_request') { $matches = array(); preg_match('/\/([a-zA-Z0-9_\-]+\/[a-zA-Z0-9_\-]+)/', $this->getExtra('remote_url'), $matches); $reference = $matches[1]; $branch = $this->getExtra('remote_branch'); } $link = 'https://github.com/' . $reference . '/'; $link .= 'blob/' . $branch . '/'; $link .= '{FILE}'; $link .= '#L{LINE}'; return $link; } /** * Handle any post-clone tasks, like applying a pull request patch on top of the branch. * @param Builder $builder * @param $cloneTo * @return bool */ protected function postCloneSetup(Builder $builder, $cloneTo) { $buildType = $this->getExtra('build_type'); $success = true; try { if (!empty($buildType) && $buildType == 'pull_request') { $remoteUrl = $this->getExtra('remote_url'); $remoteBranch = $this->getExtra('remote_branch'); $cmd = 'cd "%s" && git checkout -b phpci/' . $this->getId() . ' %s && git pull -q --no-edit %s %s'; $success = $builder->executeCommand($cmd, $cloneTo, $this->getBranch(), $remoteUrl, $remoteBranch); } } catch (\Exception $ex) { $success = false; } if ($success) { $success = parent::postCloneSetup($builder, $cloneTo); } return $success; } /** * @inheritDoc */ public function reportError(Builder $builder, $file, $line, $message) { $diffLineNumber = $this->getDiffLineNumber($builder, $file, $line); if (!is_null($diffLineNumber)) { $helper = new Github(); $repo = $this->getProject()->getReference(); $prNumber = $this->getExtra('pull_request_number'); $commit = $this->getCommitId(); if (!empty($prNumber)) { $helper->createPullRequestComment($repo, $prNumber, $commit, $file, $diffLineNumber, $message); } else { $helper->createCommitComment($repo, $commit, $file, $diffLineNumber, $message); } } } /** * Uses git diff to figure out what the diff line position is, based on the error line number. * @param Builder $builder * @param $file * @param $line * @return int|null */ protected function getDiffLineNumber(Builder $builder, $file, $line) { $builder->logExecOutput(false); $prNumber = $this->getExtra('pull_request_number'); $path = $builder->buildPath; if (!empty($prNumber)) { $builder->executeCommand('cd %s && git diff origin/%s "%s"', $path, $this->getBranch(), $file); } else { $commitId = $this->getCommitId(); $compare = $commitId == 'Manual' ? 'HEAD' : $commitId; $builder->executeCommand('cd %s && git diff %s^! "%s"', $path, $compare, $file); } $builder->logExecOutput(true); $diff = $builder->getLastOutput(); $helper = new Diff(); $lines = $helper->getLinePositions($diff); return $lines[$line]; } }